sitevision-cli 0.6.0-beta.1 → 1.0.0-beta.0

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/dist/app.js CHANGED
@@ -24,6 +24,15 @@ export default function App({ project }) {
24
24
  // slow and this component re-renders frequently).
25
25
  const signingUsername = project.devProperties?.signingUsername;
26
26
  const storedSigningPassword = useMemo(() => (signingUsername ? getSigningPassword(signingUsername) : null), [signingUsername]);
27
+ // Map a signing-capable command to the screen it lands on once the signing
28
+ // password is resolved.
29
+ const signedDestination = (command = currentCommand) => {
30
+ if (command === 'dev-signed')
31
+ return 'dev';
32
+ if (command === 'watch-signed')
33
+ return 'watch';
34
+ return 'sign';
35
+ };
27
36
  // Decide the next step once a signing password is needed: proceed if we already
28
37
  // have one this session, offer the keychain choice if one is saved, otherwise
29
38
  // prompt for manual entry.
@@ -34,7 +43,7 @@ export default function App({ project }) {
34
43
  isRetry: signingRetry,
35
44
  });
36
45
  if (step === 'proceed') {
37
- setState(command === 'dev-signed' ? 'dev' : 'sign');
46
+ setState(signedDestination(command));
38
47
  }
39
48
  else if (step === 'choice') {
40
49
  setState('signing-password-choice');
@@ -78,7 +87,7 @@ export default function App({ project }) {
78
87
  if (storedSigningPassword) {
79
88
  setSigningPassword(storedSigningPassword);
80
89
  }
81
- setState(currentCommand === 'dev-signed' ? 'dev' : 'sign');
90
+ setState(signedDestination());
82
91
  };
83
92
  const handleEnterNewSigning = () => {
84
93
  setState('signing-password-input');
@@ -88,12 +97,7 @@ export default function App({ project }) {
88
97
  if (remember && project.devProperties?.signingUsername && password) {
89
98
  saveSigningPassword(project.devProperties.signingUsername, password);
90
99
  }
91
- if (currentCommand === 'dev-signed') {
92
- setState('dev');
93
- }
94
- else {
95
- setState('sign');
96
- }
100
+ setState(signedDestination());
97
101
  };
98
102
  const handleCommandSelect = (command) => {
99
103
  setCurrentCommand(command);
@@ -135,6 +139,21 @@ export default function App({ project }) {
135
139
  routeToSigningStep(command);
136
140
  }
137
141
  break;
142
+ case 'watch':
143
+ // Build/sign-only: no deploy and no signing, so no credentials needed.
144
+ setState('watch');
145
+ break;
146
+ case 'watch-signed':
147
+ if (!project.hasDevProperties || !project.devProperties) {
148
+ console.log('\x1b[31mDevelopment properties not configured. Create a .dev_properties.json file first.\x1b[0m');
149
+ return;
150
+ }
151
+ if (!project.hasSigningProperties) {
152
+ console.log('\x1b[31mSigning credentials not configured. Run svc setup-signing first.\x1b[0m');
153
+ return;
154
+ }
155
+ routeToSigningStep(command);
156
+ break;
138
157
  case 'sign':
139
158
  if (!project.hasDevProperties || !project.devProperties) {
140
159
  console.log('\x1b[31mDevelopment properties not configured. Create a .dev_properties.json file first.\x1b[0m');
@@ -205,6 +224,23 @@ export default function App({ project }) {
205
224
  }
206
225
  : undefined }));
207
226
  }
227
+ if (state === 'watch') {
228
+ const watchSigned = currentCommand === 'watch-signed';
229
+ return (_jsx(DevScreen, { projectRoot: project.root, manifest: project.manifest, devProperties: project.devProperties, signed: watchSigned, deploy: false, onBack: () => setState('menu'), onRetryCredentials: watchSigned
230
+ ? () => {
231
+ setSigningPassword('');
232
+ // The saved password may be what failed — don't re-offer it.
233
+ setSigningRetry(true);
234
+ routeToSigningStep('watch-signed');
235
+ }
236
+ : undefined, signingCredentials: watchSigned && project.devProperties?.signingUsername
237
+ ? {
238
+ username: project.devProperties.signingUsername,
239
+ password: signingPassword,
240
+ certificateName: project.devProperties.certificateName,
241
+ }
242
+ : undefined }));
243
+ }
208
244
  if (state === 'build') {
209
245
  return (_jsx(BuildScreen, { projectRoot: project.root, manifest: project.manifest, createZip: true, onBack: () => setState('menu') }));
210
246
  }
package/dist/cli.js CHANGED
@@ -12,7 +12,7 @@ import { checkForUpdate } from './utils/version-check.js';
12
12
  import { isFirstRun, markFirstRunComplete, getLastSeenVersion, setLastSeenVersion, } from './utils/config.js';
13
13
  import { WelcomeScreen } from './components/WelcomeScreen.js';
14
14
  import { AnimatedLogo } from './components/AnimatedLogo.js';
15
- import { printBranding, BIG_LOGO_WIDTH } from './utils/branding.js';
15
+ import { printBranding, BIG_LOGO, BIG_LOGO_WIDTH, SMALL_LOGO, SMALL_LOGO_WIDTH, } from './utils/branding.js';
16
16
  const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
17
17
  const cli = meow(`
18
18
  Usage
@@ -21,7 +21,9 @@ const cli = meow(`
21
21
 
22
22
  Commands
23
23
  dev Start development server with watch mode
24
+ watch Watch and rebuild (optionally signing) without deploying
24
25
  build Build the application for production
26
+ sign Sign the app for production deployment
25
27
  deploy Deploy the application
26
28
  info Show project information
27
29
 
@@ -33,6 +35,8 @@ const cli = meow(`
33
35
  $ svc # Interactive menu
34
36
  $ svc dev
35
37
  $ svc dev --signed
38
+ $ svc watch
39
+ $ svc watch --signed
36
40
  $ svc build
37
41
  $ svc deploy --force
38
42
  $ svc deploy --production
@@ -85,10 +89,19 @@ function printMasthead(version) {
85
89
  `${spaces(gap)}${DIM}${right}${RESET}${spaces(padding)}${CYAN}│${RESET}`);
86
90
  console.log(`${CYAN}╰${border}╯${RESET}`);
87
91
  }
92
+ // Pick the widest wordmark that fits the terminal, or undefined if even the
93
+ // compact one would wrap (caller then falls back to the static masthead).
94
+ function pickIntroArt(columns) {
95
+ if (columns >= BIG_LOGO_WIDTH)
96
+ return BIG_LOGO;
97
+ if (columns >= SMALL_LOGO_WIDTH)
98
+ return SMALL_LOGO;
99
+ return undefined;
100
+ }
88
101
  // Play the one-shot animated wordmark and resolve once it finishes.
89
- async function playIntro() {
102
+ async function playIntro(art) {
90
103
  await new Promise(resolve => {
91
- const app = render(_jsx(AnimatedLogo, { onDone: () => app.unmount() }));
104
+ const app = render(_jsx(AnimatedLogo, { art: art, onDone: () => app.unmount() }));
92
105
  app.waitUntilExit().then(() => resolve(), () => resolve());
93
106
  });
94
107
  }
@@ -104,19 +117,18 @@ async function main() {
104
117
  const lastSeen = getLastSeenVersion();
105
118
  const isUpdate = !firstRun && lastSeen !== undefined && lastSeen !== pkg.version;
106
119
  // On the plain interactive `svc` (no command), play the animated wordmark
107
- // instead of the static masthead — but only when stdout is wide enough for
108
- // the art and stdin is a TTY (so it doesn't run in CI / piped input).
109
- const wantsIntro = !firstRun &&
110
- !isUpdate &&
111
- !commandName &&
112
- Boolean(process.stdin.isTTY) &&
113
- (process.stdout.columns ?? 0) >= BIG_LOGO_WIDTH;
120
+ // instead of the static masthead — sized to the terminal. Only on a TTY so it
121
+ // doesn't run in CI / piped input.
122
+ const introEligible = !firstRun && !isUpdate && !commandName && Boolean(process.stdin.isTTY);
123
+ const introArt = introEligible
124
+ ? pickIntroArt(process.stdout.columns ?? 0)
125
+ : undefined;
114
126
  if (!firstRun) {
115
127
  if (isUpdate) {
116
128
  printBranding();
117
129
  console.log(`\x1b[32m\n ✨ Updated to v${pkg.version}\x1b[0m \x1b[2m(from v${lastSeen})\x1b[0m\n`);
118
130
  }
119
- else if (!wantsIntro) {
131
+ else if (!introArt) {
120
132
  printMasthead(pkg.version);
121
133
  }
122
134
  // Record the current version so the banner shows once per upgrade.
@@ -152,8 +164,8 @@ async function main() {
152
164
  // If no command, show interactive menu (with the animated intro first when
153
165
  // the terminal can fit it).
154
166
  if (!commandName) {
155
- if (wantsIntro) {
156
- await playIntro();
167
+ if (introArt) {
168
+ await playIntro(introArt);
157
169
  }
158
170
  render(_jsx(App, { project: project }));
159
171
  return;
@@ -4,12 +4,13 @@ import type { SitevisionManifest, DevProperties, SigningCredentials } from '../t
4
4
  interface DevScreenProps {
5
5
  projectRoot: string;
6
6
  manifest: SitevisionManifest;
7
- devProperties: DevProperties;
7
+ devProperties?: DevProperties;
8
8
  signed: boolean;
9
+ deploy?: boolean;
9
10
  signingCredentials?: SigningCredentials;
10
11
  onBack?: () => void;
11
12
  onRetryCredentials?: () => void;
12
13
  }
13
- export declare function DevScreen({ projectRoot, manifest, devProperties, signed, signingCredentials, onBack, onRetryCredentials, }: DevScreenProps): React.JSX.Element;
14
+ export declare function DevScreen({ projectRoot, manifest, devProperties, signed, deploy, signingCredentials, onBack, onRetryCredentials, }: DevScreenProps): React.JSX.Element;
14
15
  export declare const devCommand: Command;
15
16
  export {};
@@ -12,7 +12,7 @@ import { setDeployPassword } from '../utils/keychain.js';
12
12
  import { resolveSigningPassword } from '../utils/signing-password.js';
13
13
  import { copyStaticToBuild, createBuildZip, cleanBuild } from '../utils/zip.js';
14
14
  import { isBundledApp, getAppType, getFullAppId, getZipPath, getSignedZipPath, } from '../utils/project-detection.js';
15
- export function DevScreen({ projectRoot, manifest, devProperties, signed, signingCredentials, onBack, onRetryCredentials, }) {
15
+ export function DevScreen({ projectRoot, manifest, devProperties, signed, deploy = true, signingCredentials, onBack, onRetryCredentials, }) {
16
16
  const { exit } = useApp();
17
17
  const [state, setState] = React.useState({
18
18
  status: 'initializing',
@@ -57,6 +57,20 @@ export function DevScreen({ projectRoot, manifest, devProperties, signed, signin
57
57
  }
58
58
  deployZipPath = signedZipPath;
59
59
  }
60
+ // Watch/build-only mode: stop after building (and signing).
61
+ if (!deploy || !devProperties) {
62
+ setState(prev => ({
63
+ ...prev,
64
+ status: 'ready',
65
+ message: signed
66
+ ? 'Signed. Watching for changes...'
67
+ : 'Built. Watching for changes...',
68
+ buildCount: prev.buildCount + 1,
69
+ lastBuildTime: buildTime,
70
+ error: undefined,
71
+ }));
72
+ return;
73
+ }
60
74
  // Deploy
61
75
  setState(prev => ({
62
76
  ...prev,
@@ -99,7 +113,7 @@ export function DevScreen({ projectRoot, manifest, devProperties, signed, signin
99
113
  error: error instanceof Error ? error.message : String(error),
100
114
  }));
101
115
  }
102
- }, [projectRoot, manifest, devProperties, signed, signingCredentials]);
116
+ }, [projectRoot, manifest, devProperties, signed, deploy, signingCredentials]);
103
117
  // In-house webpack path: copy static, zip, then sign + deploy.
104
118
  const handleBuildComplete = React.useCallback(async (result) => {
105
119
  if (!result.success) {
@@ -339,7 +353,7 @@ export function DevScreen({ projectRoot, manifest, devProperties, signed, signin
339
353
  };
340
354
  return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(StatusIndicator, { status: getStatusType(), label: getStatusLabel(), message: state.message }) }), state.warning && (_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { color: "yellow", children: ["\u26A0 ", state.warning] }) })), state.buildCount > 0 && (_jsx(Box, { marginLeft: 2, marginBottom: 1, children: _jsxs(Text, { dimColor: true, children: ["Builds: ", state.buildCount, state.lastBuildTime
341
355
  ? ` | Last build: ${state.lastBuildTime}ms`
342
- : '', signed ? ' | Signed mode' : ''] }) })), _jsx(Box, { marginLeft: 2, marginBottom: 1, children: _jsxs(Text, { dimColor: true, children: [manifest.name, " v", manifest.version] }) }), devProperties && (_jsx(Box, { marginLeft: 2, marginBottom: 1, children: _jsxs(Text, { dimColor: true, children: ["Target: ", devProperties.domain, "/", devProperties.siteName, "/", devProperties.addonName] }) })), state.status === 'error' && state.error && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(Text, { color: "red", children: state.error }) })), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [state.status === 'error' && onRetryCredentials && (_jsx(Text, { dimColor: true, children: "Press r to retry with new credentials" })), onBack ? (_jsx(Text, { dimColor: true, children: "Press q or Esc to return to menu (Ctrl+C to stop process)" })) : (_jsx(Text, { dimColor: true, children: "Press Ctrl+C to stop" }))] })] }));
356
+ : '', signed ? ' | Signed mode' : ''] }) })), _jsx(Box, { marginLeft: 2, marginBottom: 1, children: _jsxs(Text, { dimColor: true, children: [manifest.name, " v", manifest.version] }) }), deploy && devProperties && (_jsx(Box, { marginLeft: 2, marginBottom: 1, children: _jsxs(Text, { dimColor: true, children: ["Target: ", devProperties.domain, "/", devProperties.siteName, "/", devProperties.addonName] }) })), state.status === 'error' && state.error && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(Text, { color: "red", children: state.error }) })), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [state.status === 'error' && onRetryCredentials && (_jsx(Text, { dimColor: true, children: "Press r to retry with new credentials" })), onBack ? (_jsx(Text, { dimColor: true, children: "Press q or Esc to return to menu (Ctrl+C to stop process)" })) : (_jsx(Text, { dimColor: true, children: "Press Ctrl+C to stop" }))] })] }));
343
357
  }
344
358
  export const devCommand = {
345
359
  name: 'dev',
@@ -1,4 +1,5 @@
1
1
  import { devCommand } from './dev.js';
2
+ import { watchCommand } from './watch.js';
2
3
  import { buildCommand } from './build.js';
3
4
  import { deployCommand } from './deploy.js';
4
5
  import { infoCommand } from './info.js';
@@ -6,6 +7,7 @@ import { setupSigningCommand } from './setup-signing.js';
6
7
  import { signCommand } from './sign.js';
7
8
  export const commands = [
8
9
  devCommand,
10
+ watchCommand,
9
11
  buildCommand,
10
12
  signCommand,
11
13
  deployCommand,
@@ -0,0 +1,2 @@
1
+ import { type Command } from './types.js';
2
+ export declare const watchCommand: Command;
@@ -0,0 +1,44 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { render } from 'ink';
3
+ import { DevScreen } from './dev.js';
4
+ import { resolveSigningPassword } from '../utils/signing-password.js';
5
+ export const watchCommand = {
6
+ name: 'watch',
7
+ description: 'Watch and rebuild (optionally signing) without deploying',
8
+ requiresProject: true,
9
+ flags: {
10
+ signed: {
11
+ type: 'boolean',
12
+ description: 'Sign after each build',
13
+ alias: 's',
14
+ default: false,
15
+ },
16
+ },
17
+ async execute({ project, flags }) {
18
+ const signed = Boolean(flags['signed']);
19
+ let signingCredentials;
20
+ // Signed mode: resolve signing credentials (keychain → env → prompt).
21
+ // No deploy credentials are needed — watch never deploys.
22
+ if (signed) {
23
+ if (!project.hasSigningProperties ||
24
+ !project.devProperties?.signingUsername) {
25
+ console.log('\n\x1b[33mSigning credentials not configured.\x1b[0m');
26
+ console.log('Run \x1b[36msetup-signing\x1b[0m to configure credentials.\n');
27
+ return;
28
+ }
29
+ const signingUsername = project.devProperties.signingUsername;
30
+ const password = await resolveSigningPassword(signingUsername);
31
+ if (!password) {
32
+ console.log('\x1b[31mError: Password is required for signed mode\x1b[0m');
33
+ return;
34
+ }
35
+ signingCredentials = {
36
+ username: signingUsername,
37
+ password,
38
+ certificateName: project.devProperties.certificateName,
39
+ };
40
+ }
41
+ const { waitUntilExit } = render(_jsx(DevScreen, { projectRoot: project.root, manifest: project.manifest, devProperties: project.devProperties, signed: signed, deploy: false, signingCredentials: signingCredentials }));
42
+ await waitUntilExit();
43
+ },
44
+ };
@@ -1,9 +1,10 @@
1
1
  interface Props {
2
+ art?: string[];
2
3
  onDone: () => void;
3
4
  }
4
5
  /**
5
6
  * One-shot startup flair: wipes the big wordmark in left-to-right while a
6
7
  * rainbow gradient drifts across it, then calls `onDone`. Purely decorative.
7
8
  */
8
- export declare function AnimatedLogo({ onDone }: Props): import("react").JSX.Element;
9
+ export declare function AnimatedLogo({ art, onDone }: Props): import("react").JSX.Element;
9
10
  export {};
@@ -1,15 +1,17 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Fragment, useEffect, useRef, useState } from 'react';
3
3
  import { Box, Text } from 'ink';
4
- import { AUTHOR, BIG_LOGO, BIG_LOGO_WIDTH } from '../utils/branding.js';
4
+ import { AUTHOR, BIG_LOGO } from '../utils/branding.js';
5
5
  const FRAME_MS = 45;
6
6
  const SWEEP_COLS_PER_FRAME = 7; // how fast the wipe edge moves left → right
7
7
  const BAND = 18; // width of the rainbow zone trailing the sweep edge
8
8
  const HOLD_FRAMES = 6; // frames to hold the fully-settled logo before finishing
9
- // The sweep edge runs past the right side by BAND so the rainbow zone trails
10
- // all the way off, leaving every character settled to the terminal default.
11
- const SWEEP_FRAMES = Math.ceil((BIG_LOGO_WIDTH + BAND) / SWEEP_COLS_PER_FRAME);
12
- const TOTAL_FRAMES = SWEEP_FRAMES + HOLD_FRAMES;
9
+ // Frames to fully reveal and settle art `width` columns wide. The sweep edge
10
+ // runs past the right side by BAND so the rainbow zone trails all the way off,
11
+ // leaving every character settled to the terminal default.
12
+ function framesFor(width) {
13
+ return Math.ceil((width + BAND) / SWEEP_COLS_PER_FRAME) + HOLD_FRAMES;
14
+ }
13
15
  // Convert HSL (h in degrees, s/l in 0..1) to a #rrggbb string for ink/chalk.
14
16
  function hslToHex(h, s, l) {
15
17
  const hue = h / 360;
@@ -59,9 +61,11 @@ function buildSpans(line, y, frame, edge) {
59
61
  * One-shot startup flair: wipes the big wordmark in left-to-right while a
60
62
  * rainbow gradient drifts across it, then calls `onDone`. Purely decorative.
61
63
  */
62
- export function AnimatedLogo({ onDone }) {
64
+ export function AnimatedLogo({ art = BIG_LOGO, onDone }) {
63
65
  const [frame, setFrame] = useState(0);
64
66
  const intervalRef = useRef(undefined);
67
+ const width = Math.max(...art.map(line => [...line].length));
68
+ const total = framesFor(width);
65
69
  useEffect(() => {
66
70
  intervalRef.current = setInterval(() => {
67
71
  setFrame(current => current + 1);
@@ -73,11 +77,11 @@ export function AnimatedLogo({ onDone }) {
73
77
  // Stop the loop and notify the parent exactly once, when the last frame is
74
78
  // reached. Kept out of the setFrame updater so that updater stays pure.
75
79
  useEffect(() => {
76
- if (frame >= TOTAL_FRAMES) {
80
+ if (frame >= total) {
77
81
  clearInterval(intervalRef.current);
78
82
  onDone();
79
83
  }
80
- }, [frame, onDone]);
84
+ }, [frame, total, onDone]);
81
85
  const edge = (frame + 1) * SWEEP_COLS_PER_FRAME;
82
- return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [BIG_LOGO.map((line, y) => (_jsx(Text, { children: buildSpans(line, y, frame, edge).map((span, index) => (_jsx(Fragment, { children: span.color ? (_jsx(Text, { color: span.color, children: span.text })) : (_jsx(Text, { children: span.text })) }, index))) }, y))), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { dimColor: true, children: ' a tool by ' }), _jsx(Text, { bold: true, children: AUTHOR })] })] }));
86
+ return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [art.map((line, y) => (_jsx(Text, { children: buildSpans(line, y, frame, edge).map((span, index) => (_jsx(Fragment, { children: span.color ? (_jsx(Text, { color: span.color, children: span.text })) : (_jsx(Text, { children: span.text })) }, index))) }, y))), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { dimColor: true, children: ' a tool by ' }), _jsx(Text, { bold: true, children: AUTHOR })] })] }));
83
87
  }
@@ -16,6 +16,16 @@ export function MainMenu({ project, onSelect }) {
16
16
  value: 'dev-signed',
17
17
  description: 'Development with automatic signing',
18
18
  },
19
+ {
20
+ label: '👀 Watch',
21
+ value: 'watch',
22
+ description: 'Rebuild on change without deploying',
23
+ },
24
+ {
25
+ label: '👀 Watch (Signed)',
26
+ value: 'watch-signed',
27
+ description: 'Rebuild and sign on change without deploying',
28
+ },
19
29
  {
20
30
  label: '🔨 Build',
21
31
  value: 'build',
@@ -14,6 +14,13 @@ export declare const AUTHOR = "Rasmus S\u00F6derstr\u00F6m";
14
14
  export declare const BIG_LOGO: string[];
15
15
  /** Display width of the widest BIG_LOGO line. */
16
16
  export declare const BIG_LOGO_WIDTH: number;
17
+ /**
18
+ * Compact "Sitevision CLI" wordmark, animated on terminals too narrow for
19
+ * BIG_LOGO. ~72 columns wide.
20
+ */
21
+ export declare const SMALL_LOGO: string[];
22
+ /** Display width of the widest SMALL_LOGO line. */
23
+ export declare const SMALL_LOGO_WIDTH: number;
17
24
  /**
18
25
  * Print the logo + author line straight to stdout (non-interactive), mirroring
19
26
  * how the masthead is printed. Used for the update banner.
@@ -35,6 +35,17 @@ export const BIG_LOGO = [
35
35
  ];
36
36
  /** Display width of the widest BIG_LOGO line. */
37
37
  export const BIG_LOGO_WIDTH = Math.max(...BIG_LOGO.map(line => line.length));
38
+ /**
39
+ * Compact "Sitevision CLI" wordmark, animated on terminals too narrow for
40
+ * BIG_LOGO. ~72 columns wide.
41
+ */
42
+ export const SMALL_LOGO = [
43
+ '▄█████ ▄▄ ▄▄▄▄▄▄ ▄▄▄▄▄ ▄▄ ▄▄ ▄▄ ▄▄▄▄ ▄▄ ▄▄▄ ▄▄ ▄▄ ▄█████ ██ ██ ',
44
+ '▀▀▀▄▄▄ ██ ██ ██▄▄ ██▄██ ██ ███▄▄ ██ ██▀██ ███▄██ ██ ██ ██ ',
45
+ '█████▀ ██ ██ ██▄▄▄ ▀█▀ ██ ▄▄██▀ ██ ▀███▀ ██ ▀██ ▀█████ ██████ ██ ',
46
+ ];
47
+ /** Display width of the widest SMALL_LOGO line. */
48
+ export const SMALL_LOGO_WIDTH = Math.max(...SMALL_LOGO.map(line => [...line].length));
38
49
  /**
39
50
  * Print the logo + author line straight to stdout (non-interactive), mirroring
40
51
  * how the masthead is printed. Used for the update banner.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sitevision-cli",
3
- "version": "0.6.0-beta.1",
3
+ "version": "1.0.0-beta.0",
4
4
  "license": "MIT",
5
5
  "bin": {
6
6
  "svc": "dist/cli.js"