sitevision-cli 1.0.0-beta.12 → 1.0.0-beta.14

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.
Files changed (43) hide show
  1. package/dist/cli.js +70 -41
  2. package/dist/commands/build.js +1 -1
  3. package/dist/commands/dev.d.ts +8 -10
  4. package/dist/commands/dev.js +75 -390
  5. package/dist/commands/watch.js +5 -23
  6. package/dist/components/AuthLoginScreen.js +4 -3
  7. package/dist/components/DevPropertiesForm.js +6 -3
  8. package/dist/components/PasswordInput.js +2 -1
  9. package/dist/shell/AddonPicker.d.ts +14 -0
  10. package/dist/shell/AddonPicker.js +54 -0
  11. package/dist/shell/CommandPalette.d.ts +8 -0
  12. package/dist/shell/CommandPalette.js +63 -0
  13. package/dist/shell/ConfigForm.d.ts +35 -0
  14. package/dist/shell/ConfigForm.js +472 -0
  15. package/dist/shell/Frame.d.ts +52 -0
  16. package/dist/shell/Frame.js +98 -0
  17. package/dist/shell/Settings.d.ts +6 -0
  18. package/dist/shell/Settings.js +96 -0
  19. package/dist/shell/Shell.d.ts +8 -0
  20. package/dist/shell/Shell.js +520 -0
  21. package/dist/shell/Tabs.d.ts +36 -0
  22. package/dist/shell/Tabs.js +85 -0
  23. package/dist/shell/actions.d.ts +45 -0
  24. package/dist/shell/actions.js +0 -0
  25. package/dist/types/index.d.ts +12 -2
  26. package/dist/utils/config.d.ts +10 -0
  27. package/dist/utils/config.js +14 -0
  28. package/dist/utils/environments.d.ts +20 -0
  29. package/dist/utils/environments.js +74 -0
  30. package/dist/utils/i18n.d.ts +12 -0
  31. package/dist/utils/i18n.js +263 -0
  32. package/dist/utils/oauth2-auth.d.ts +26 -1
  33. package/dist/utils/oauth2-auth.js +75 -32
  34. package/dist/utils/project-detection.d.ts +23 -1
  35. package/dist/utils/project-detection.js +124 -51
  36. package/dist/utils/sitevision-api.d.ts +35 -0
  37. package/dist/utils/sitevision-api.js +74 -1
  38. package/dist/utils/tasks.d.ts +48 -0
  39. package/dist/utils/tasks.js +371 -0
  40. package/dist/utils/workspace.d.ts +8 -0
  41. package/dist/utils/workspace.js +48 -0
  42. package/package.json +1 -1
  43. package/readme.md +76 -24
package/dist/cli.js CHANGED
@@ -1,22 +1,24 @@
1
1
  #!/usr/bin/env node
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
3
3
  import { render } from 'ink';
4
4
  import { Text, Box } from 'ink';
5
5
  import meow from 'meow';
6
6
  import { readFileSync } from 'node:fs';
7
- import App from './app.js';
7
+ import { Shell } from './shell/Shell.js';
8
8
  import { getCommand } from './commands/index.js';
9
- import { requireProject, migrateLegacyPassword, } from './utils/project-detection.js';
9
+ import { requireProject, detectProject, migrateLegacyPassword, } from './utils/project-detection.js';
10
+ import { discoverApps } from './utils/workspace.js';
10
11
  import { promptYesNo } from './utils/password-prompt.js';
11
12
  import { checkForUpdate } from './utils/version-check.js';
12
- import { isFirstRun, markFirstRunComplete, getLastSeenVersion, setLastSeenVersion, } from './utils/config.js';
13
+ import { isFirstRun, markFirstRunComplete, getLastSeenVersion, setLastSeenVersion, getSettings, } from './utils/config.js';
14
+ import { setLanguage } from './utils/i18n.js';
13
15
  import { WelcomeScreen } from './components/WelcomeScreen.js';
14
16
  import { AnimatedLogo } from './components/AnimatedLogo.js';
15
17
  import { printBranding, BIG_LOGO, BIG_LOGO_WIDTH, SMALL_LOGO, SMALL_LOGO_WIDTH, } from './utils/branding.js';
16
18
  const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
17
19
  const cli = meow(`
18
20
  Usage
19
- $ svc Start interactive menu
21
+ $ svc Open the interactive shell (app or workspace)
20
22
  $ svc <command> [options]
21
23
 
22
24
  Commands
@@ -32,7 +34,7 @@ const cli = meow(`
32
34
  --version Show version number
33
35
 
34
36
  Examples
35
- $ svc # Interactive menu
37
+ $ svc # Shell: run inside an app, or at the repo root
36
38
  $ svc dev
37
39
  $ svc dev --signed
38
40
  $ svc watch
@@ -67,6 +69,8 @@ const cli = meow(`
67
69
  },
68
70
  });
69
71
  const [commandName, ...args] = cli.input;
72
+ const settings = getSettings();
73
+ setLanguage(settings.language);
70
74
  const CYAN = '\x1b[36m';
71
75
  const BOLD = '\x1b[1m';
72
76
  const DIM = '\x1b[2m';
@@ -95,8 +99,12 @@ function printMasthead(version) {
95
99
  `${spaces(gap)}${DIM}${right}${RESET}${spaces(padding)}${CYAN}│${RESET}`);
96
100
  console.log(`${CYAN}╰${border}╯${RESET}`);
97
101
  }
102
+ function fail(message, hint) {
103
+ render(_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsxs(Text, { color: "red", children: ["Error: ", message] }), _jsx(Text, { dimColor: true, children: hint })] }));
104
+ process.exit(1);
105
+ }
98
106
  // Pick the widest wordmark that fits the terminal, or undefined if even the
99
- // compact one would wrap (caller then falls back to the static masthead).
107
+ // compact one would wrap.
100
108
  function pickIntroArt(columns) {
101
109
  if (columns >= BIG_LOGO_WIDTH)
102
110
  return BIG_LOGO;
@@ -111,6 +119,26 @@ async function playIntro(art) {
111
119
  app.waitUntilExit().then(() => resolve(), () => resolve());
112
120
  });
113
121
  }
122
+ // Run the full-screen shell on the alternate screen buffer so the scrollback
123
+ // is untouched, and restore it on exit. The animated wordmark plays first,
124
+ // inside the same buffer, when the terminal is wide enough for it.
125
+ async function runShell(apps, workspaceRoot) {
126
+ process.stdout.write('\x1b[?1049h\x1b[H');
127
+ try {
128
+ const art = process.stdin.isTTY && settings.introAnimation
129
+ ? pickIntroArt(process.stdout.columns ?? 0)
130
+ : undefined;
131
+ if (art) {
132
+ await playIntro(art);
133
+ process.stdout.write('\x1b[2J\x1b[H');
134
+ }
135
+ const app = render(_jsx(Shell, { apps: apps, workspaceRoot: workspaceRoot, version: pkg.version }));
136
+ await app.waitUntilExit();
137
+ }
138
+ finally {
139
+ process.stdout.write('\x1b[?1049l');
140
+ }
141
+ }
114
142
  async function main() {
115
143
  // On the very first run we show a dedicated welcome screen instead of the
116
144
  // masthead, so the branding is the moment. Only when stdin is a TTY — the
@@ -122,19 +150,12 @@ async function main() {
122
150
  // silently rather than claiming an update happened.
123
151
  const lastSeen = getLastSeenVersion();
124
152
  const isUpdate = !firstRun && lastSeen !== undefined && lastSeen !== pkg.version;
125
- // On the plain interactive `svc` (no command), play the animated wordmark
126
- // instead of the static masthead — sized to the terminal. Only on a TTY so it
127
- // doesn't run in CI / piped input.
128
- const introEligible = !firstRun && !isUpdate && !commandName && Boolean(process.stdin.isTTY);
129
- const introArt = introEligible
130
- ? pickIntroArt(process.stdout.columns ?? 0)
131
- : undefined;
132
153
  if (!firstRun) {
133
154
  if (isUpdate) {
134
155
  printBranding();
135
156
  console.log(`\x1b[32m\n ✨ Updated to v${pkg.version}\x1b[0m \x1b[2m(from v${lastSeen})\x1b[0m\n`);
136
157
  }
137
- else if (!introArt) {
158
+ else if (commandName) {
138
159
  printMasthead(pkg.version);
139
160
  }
140
161
  // Record the current version so the banner shows once per upgrade.
@@ -145,14 +166,44 @@ async function main() {
145
166
  console.log(`\x1b[33m ↑ update available: ${pkg.version} → ${latestVersion} (run: npm i -g ${pkg.name})\x1b[0m`);
146
167
  }
147
168
  }
169
+ // No command: the shell. Inside an app it is single-app mode; anywhere
170
+ // above one or more apps it is workspace mode.
171
+ if (!commandName) {
172
+ let project = null;
173
+ try {
174
+ project = detectProject();
175
+ }
176
+ catch (error) {
177
+ fail(error.message, 'Fix the manifest and try again');
178
+ }
179
+ if (!project) {
180
+ const apps = discoverApps(process.cwd());
181
+ if (apps.length === 0) {
182
+ fail('No Sitevision apps found here.', 'Run svc inside an app directory (manifest.json) or at the root of a repo that contains apps.');
183
+ }
184
+ await runShell(apps, process.cwd());
185
+ return;
186
+ }
187
+ if (firstRun) {
188
+ await new Promise(resolve => {
189
+ const app = render(_jsx(WelcomeScreen, { project: project, onComplete: () => {
190
+ markFirstRunComplete();
191
+ setLastSeenVersion(pkg.version);
192
+ app.unmount();
193
+ } }));
194
+ app.waitUntilExit().then(() => resolve(), () => resolve());
195
+ });
196
+ }
197
+ await runShell([project]);
198
+ return;
199
+ }
148
200
  // Check if we're in a Sitevision project
149
201
  const project = (() => {
150
202
  try {
151
203
  return requireProject();
152
204
  }
153
205
  catch (error) {
154
- render(_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsxs(Text, { color: "red", children: ["Error: ", error.message] }), _jsx(Text, { dimColor: true, children: "Make sure you're in a Sitevision project directory" })] }));
155
- process.exit(1);
206
+ return fail(error.message, "Make sure you're in a Sitevision project directory");
156
207
  }
157
208
  })();
158
209
  // --token / --cookie override the resolved bearer token / session cookie for
@@ -171,27 +222,6 @@ async function main() {
171
222
  console.log('\x1b[33m--token/--cookie needs a .dev_properties.json (domain, site, addon) to deploy against.\x1b[0m');
172
223
  }
173
224
  }
174
- // First run: show the welcome (branding + optional signing-password save),
175
- // then continue to the normal flow once the user dismisses it.
176
- if (firstRun) {
177
- await new Promise(resolve => {
178
- const app = render(_jsx(WelcomeScreen, { project: project, onComplete: () => {
179
- markFirstRunComplete();
180
- setLastSeenVersion(pkg.version);
181
- app.unmount();
182
- } }));
183
- app.waitUntilExit().then(() => resolve(), () => resolve());
184
- });
185
- }
186
- // If no command, show interactive menu (with the animated intro first when
187
- // the terminal can fit it).
188
- if (!commandName) {
189
- if (introArt) {
190
- await playIntro(introArt);
191
- }
192
- render(_jsx(App, { project: project }));
193
- return;
194
- }
195
225
  // Get the command
196
226
  const command = getCommand(commandName);
197
227
  if (!command) {
@@ -199,9 +229,8 @@ async function main() {
199
229
  process.exit(1);
200
230
  }
201
231
  // Offer to migrate a legacy plaintext password into the OS keychain.
202
- // Interactive `svc` handles this in SetupFlow; this covers direct commands
203
- // (svc deploy/dev/sign/…). Skip on non-TTY stdin (e.g. CI) where prompting
204
- // would fail — the plaintext password is still used for this run.
232
+ // Skip on non-TTY stdin (e.g. CI) where prompting would fail — the
233
+ // plaintext password is still used for this run.
205
234
  if (project.hasLegacyPassword && process.stdin.isTTY) {
206
235
  console.log('\n\x1b[33m⚠ Plaintext password found in .dev_properties.json\x1b[0m');
207
236
  const move = await promptYesNo('Move it to the OS keychain and remove it from the file? (y/N): ');
@@ -87,7 +87,7 @@ export function BuildScreen({ projectRoot, manifest, createZip = true, onBack, }
87
87
  const runner = new WebpackRunner(projectRoot, {
88
88
  mode: 'production',
89
89
  cssPrefix: manifest.id,
90
- restApp: appType === 'rest',
90
+ restApp: appType !== 'web' && appType !== 'widget',
91
91
  });
92
92
  const result = await runner.run();
93
93
  await runner.close();
@@ -1,16 +1,14 @@
1
1
  import React from 'react';
2
2
  import { type Command } from './types.js';
3
- import type { SitevisionManifest, DevProperties, SigningCredentials } from '../types/index.js';
3
+ import { type DevOptions } from '../utils/tasks.js';
4
+ import type { ProjectInfo, SigningCredentials } from '../types/index.js';
4
5
  interface DevScreenProps {
5
- projectRoot: string;
6
- manifest: SitevisionManifest;
7
- devProperties?: DevProperties;
8
- signed: boolean;
9
- deploy?: boolean;
10
- signingCredentials?: SigningCredentials;
11
- onBack?: () => void;
12
- onRetryCredentials?: () => void;
6
+ project: ProjectInfo;
7
+ options: DevOptions;
13
8
  }
14
- export declare function DevScreen({ projectRoot, manifest, devProperties, signed, deploy, signingCredentials, onBack, onRetryCredentials, }: DevScreenProps): React.JSX.Element;
9
+ /** Standalone `svc dev` / `svc watch`: one task, its log, Ctrl+C or q to stop. */
10
+ export declare function DevScreen({ project, options }: DevScreenProps): React.JSX.Element;
11
+ /** Resolve signing credentials for signed dev/watch, prompting if needed. */
12
+ export declare function resolveSigningForCli(project: ProjectInfo): Promise<SigningCredentials | undefined>;
15
13
  export declare const devCommand: Command;
16
14
  export {};