sitevision-cli 1.0.0-beta.3 → 1.0.0-beta.31

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 (72) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/dist/app.d.ts +1 -1
  3. package/dist/app.js +59 -8
  4. package/dist/cli.js +125 -40
  5. package/dist/commands/build.js +1 -1
  6. package/dist/commands/deploy.d.ts +2 -2
  7. package/dist/commands/deploy.js +137 -28
  8. package/dist/commands/dev.d.ts +8 -10
  9. package/dist/commands/dev.js +70 -371
  10. package/dist/commands/watch.js +5 -23
  11. package/dist/components/AnimatedLogo.js +8 -2
  12. package/dist/components/AuthLoginScreen.d.ts +21 -0
  13. package/dist/components/AuthLoginScreen.js +90 -0
  14. package/dist/components/DevPropertiesForm.d.ts +2 -1
  15. package/dist/components/DevPropertiesForm.js +198 -33
  16. package/dist/components/MainMenu.js +5 -0
  17. package/dist/components/PasswordInput.js +2 -1
  18. package/dist/components/SetupFlow.d.ts +2 -1
  19. package/dist/components/SetupFlow.js +99 -10
  20. package/dist/shell/AddonPicker.d.ts +14 -0
  21. package/dist/shell/AddonPicker.js +54 -0
  22. package/dist/shell/Changelog.d.ts +10 -0
  23. package/dist/shell/Changelog.js +44 -0
  24. package/dist/shell/CommandPalette.d.ts +12 -0
  25. package/dist/shell/CommandPalette.js +63 -0
  26. package/dist/shell/ConfigForm.d.ts +36 -0
  27. package/dist/shell/ConfigForm.js +558 -0
  28. package/dist/shell/Frame.d.ts +59 -0
  29. package/dist/shell/Frame.js +135 -0
  30. package/dist/shell/Help.d.ts +9 -0
  31. package/dist/shell/Help.js +95 -0
  32. package/dist/shell/Popover.d.ts +12 -0
  33. package/dist/shell/Popover.js +15 -0
  34. package/dist/shell/Settings.d.ts +6 -0
  35. package/dist/shell/Settings.js +96 -0
  36. package/dist/shell/Shell.d.ts +10 -0
  37. package/dist/shell/Shell.js +622 -0
  38. package/dist/shell/Tabs.d.ts +36 -0
  39. package/dist/shell/Tabs.js +90 -0
  40. package/dist/shell/actions.d.ts +48 -0
  41. package/dist/shell/actions.js +0 -0
  42. package/dist/types/index.d.ts +37 -3
  43. package/dist/utils/config.d.ts +10 -0
  44. package/dist/utils/config.js +14 -0
  45. package/dist/utils/environments.d.ts +20 -0
  46. package/dist/utils/environments.js +74 -0
  47. package/dist/utils/i18n.d.ts +12 -0
  48. package/dist/utils/i18n.js +314 -0
  49. package/dist/utils/jsonc.d.ts +19 -0
  50. package/dist/utils/jsonc.js +74 -0
  51. package/dist/utils/keychain.d.ts +9 -0
  52. package/dist/utils/keychain.js +54 -0
  53. package/dist/utils/oauth2-auth.d.ts +64 -0
  54. package/dist/utils/oauth2-auth.js +242 -0
  55. package/dist/utils/password-prompt.d.ts +5 -0
  56. package/dist/utils/password-prompt.js +28 -0
  57. package/dist/utils/process-runner.d.ts +13 -4
  58. package/dist/utils/process-runner.js +63 -37
  59. package/dist/utils/project-detection.d.ts +90 -4
  60. package/dist/utils/project-detection.js +389 -63
  61. package/dist/utils/session-cookie-auth.d.ts +35 -0
  62. package/dist/utils/session-cookie-auth.js +99 -0
  63. package/dist/utils/sitevision-api.d.ts +72 -5
  64. package/dist/utils/sitevision-api.js +220 -38
  65. package/dist/utils/sitevision-scripts-runner.d.ts +2 -1
  66. package/dist/utils/sitevision-scripts-runner.js +18 -7
  67. package/dist/utils/tasks.d.ts +50 -0
  68. package/dist/utils/tasks.js +439 -0
  69. package/dist/utils/workspace.d.ts +17 -0
  70. package/dist/utils/workspace.js +67 -0
  71. package/package.json +5 -2
  72. package/readme.md +103 -121
package/CHANGELOG.md ADDED
@@ -0,0 +1,57 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0-beta.31
4
+
5
+ - The help panel (`?`) now starts with a short guide to the pane you are in:
6
+ what it shows, how the values relate, and which keys apply. The Config guide
7
+ explains how local, shared and workspace settings layer on top of each
8
+ other. The panel scrolls when it does not fit.
9
+ - Updated dependencies.
10
+
11
+ ## 1.0.0-beta.30
12
+
13
+ - Dev and watch no longer rebuild on file events that change nothing, such as
14
+ editor metadata, swap files or `.DS_Store`. Ignored events are logged as
15
+ warnings so a stray trigger can be traced.
16
+ - The log names the event and path of the file that started a rebuild, for
17
+ example `change src/index.tsx`.
18
+
19
+ ## 1.0.0-beta.29
20
+
21
+ - After an update, the shell opens What's new with the changes since the
22
+ version you last ran.
23
+
24
+ ## 1.0.0-beta.28
25
+
26
+ ## 1.0.0-beta.27
27
+
28
+ - Popups float over the screen instead of replacing the content pane: the
29
+ command palette, settings, addon picker, confirmations and prompts.
30
+ - `?` opens a help panel with every key, plus the keys for the current tab.
31
+ - What's new in the command palette shows this changelog.
32
+
33
+ ## 1.0.0-beta.26
34
+
35
+ - No functional changes.
36
+
37
+ ## 1.0.0-beta.25
38
+
39
+ - Deploying to an addon that does not exist yet now offers to create it and
40
+ deploy again. If the addon list cannot be read, the error suggests logging in
41
+ again instead, since an expired session fails the same way.
42
+ - A Create addon action appears in the command palette when a deploy has found
43
+ the addon missing.
44
+ - Creating a RESTApp or MCPServer addon no longer sends a category, which only
45
+ WebApp and widget addons use.
46
+
47
+ ## 1.0.0-beta.24
48
+
49
+ - Deploying to a non-production environment uploads the signed zip when it is at
50
+ least as new as the build. The log names the zip that was uploaded.
51
+ - `x` in the Log tab wraps long lines immediately, and wrapped lines no longer
52
+ push the newest line out of view.
53
+ - Keys: switching environment moved from `E` to `v`, and refreshing versions
54
+ from `R` to `r`. Tab in the Config form moves between fields without leaving
55
+ the form.
56
+ - The bottom bar now shows force deploy (`P`), stop, config, login and settings.
57
+ - Running commands are stopped when `svc` exits.
package/dist/app.d.ts CHANGED
@@ -2,5 +2,5 @@ import { type ProjectInfo } from './utils/project-detection.js';
2
2
  type Props = {
3
3
  project: ProjectInfo;
4
4
  };
5
- export default function App({ project }: Props): import("react").JSX.Element | null;
5
+ export default function App({ project: initialProject }: Props): import("react").JSX.Element | null;
6
6
  export {};
package/dist/app.js CHANGED
@@ -1,8 +1,10 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useMemo, useState } from 'react';
2
+ import { useCallback, useMemo, useState } from 'react';
3
+ import { detectProject } from './utils/project-detection.js';
3
4
  import { MainMenu } from './components/MainMenu.js';
4
5
  import { InfoScreen } from './components/InfoScreen.js';
5
6
  import { SetupFlow } from './components/SetupFlow.js';
7
+ import { DevPropertiesForm } from './components/DevPropertiesForm.js';
6
8
  import { PasswordInput } from './components/PasswordInput.js';
7
9
  import { KeychainPasswordChoice } from './components/KeychainPasswordChoice.js';
8
10
  import { decideSigningStep } from './utils/signing-step.js';
@@ -12,7 +14,23 @@ import { DeployScreen } from './commands/deploy.js';
12
14
  import { SignScreen } from './commands/sign.js';
13
15
  import { SigningPropertiesForm } from './components/SigningPropertiesForm.js';
14
16
  import { getSigningPassword, setDeployPassword as saveDeployPassword, setSigningPassword as saveSigningPassword, } from './utils/keychain.js';
15
- export default function App({ project }) {
17
+ const NONBASIC_DEV_UNSUPPORTED = '\x1b[33mdev/watch support only basic auth. Use `svc deploy` for OAuth2/cookie.\x1b[0m';
18
+ export default function App({ project: initialProject }) {
19
+ // The project is loaded once at startup, but setup flows write new values to
20
+ // disk and the OS keychain. Hold it in state so we can re-detect after setup
21
+ // and pick up those changes (e.g. saved passwords) without restarting the CLI.
22
+ const [project, setProject] = useState(initialProject);
23
+ const reloadProject = useCallback(() => {
24
+ try {
25
+ const refreshed = detectProject(initialProject.root);
26
+ if (refreshed)
27
+ setProject(refreshed);
28
+ }
29
+ catch {
30
+ // Re-detection failed (e.g. manifest became unparseable mid-session) —
31
+ // keep the existing in-memory project rather than crashing.
32
+ }
33
+ }, [initialProject.root]);
16
34
  const [state, setState] = useState('setup');
17
35
  const [currentCommand, setCurrentCommand] = useState('');
18
36
  const [signingPassword, setSigningPassword] = useState('');
@@ -54,10 +72,18 @@ export default function App({ project }) {
54
72
  };
55
73
  // Check if dev password is available (either from file or session)
56
74
  const hasDevPassword = Boolean(project.devProperties?.password || devPassword);
75
+ // OAuth2 / cookie configs authenticate with a token or session resolved at
76
+ // deploy time, so they need no basic password. `svc dev`/`watch` stay basic.
77
+ const authMethod = project.devProperties?.authMethod ?? 'basic';
78
+ const isTokenAuth = authMethod === 'oauth2' || authMethod === 'cookie';
79
+ const deployAuthReady = isTokenAuth || hasDevPassword;
57
80
  // Get effective dev properties with session password if needed
58
81
  const getEffectiveDevProperties = () => {
59
82
  if (!project.devProperties)
60
83
  return undefined;
84
+ // Non-basic configs authenticate by token/cookie — never graft a password.
85
+ if (isTokenAuth)
86
+ return project.devProperties;
61
87
  if (project.devProperties.password)
62
88
  return project.devProperties;
63
89
  return { ...project.devProperties, password: devPassword };
@@ -110,11 +136,22 @@ export default function App({ project }) {
110
136
  case 'setup-signing':
111
137
  setState('setup-signing');
112
138
  break;
139
+ case 'change-auth':
140
+ if (!project.hasDevProperties || !project.devProperties) {
141
+ console.log('\x1b[31mDevelopment properties not configured. Create a .dev_properties.json file first.\x1b[0m');
142
+ return;
143
+ }
144
+ setState('change-auth-method');
145
+ break;
113
146
  case 'dev':
114
147
  if (!project.hasDevProperties || !project.devProperties) {
115
148
  console.log('\x1b[31mDevelopment properties not configured. Create a .dev_properties.json file first.\x1b[0m');
116
149
  return;
117
150
  }
151
+ if (isTokenAuth) {
152
+ console.log(NONBASIC_DEV_UNSUPPORTED);
153
+ return;
154
+ }
118
155
  if (!hasDevPassword) {
119
156
  setState('dev-password-input');
120
157
  }
@@ -131,6 +168,10 @@ export default function App({ project }) {
131
168
  console.log('\x1b[31mSigning credentials not configured. Run svc setup-signing first.\x1b[0m');
132
169
  return;
133
170
  }
171
+ if (isTokenAuth) {
172
+ console.log(NONBASIC_DEV_UNSUPPORTED);
173
+ return;
174
+ }
134
175
  // Need both dev password and signing password
135
176
  if (!hasDevPassword) {
136
177
  setState('dev-password-input');
@@ -152,6 +193,10 @@ export default function App({ project }) {
152
193
  console.log('\x1b[31mSigning credentials not configured. Run svc setup-signing first.\x1b[0m');
153
194
  return;
154
195
  }
196
+ if (isTokenAuth) {
197
+ console.log(NONBASIC_DEV_UNSUPPORTED);
198
+ return;
199
+ }
155
200
  routeToSigningStep(command);
156
201
  break;
157
202
  case 'sign':
@@ -175,7 +220,7 @@ export default function App({ project }) {
175
220
  console.log('\x1b[31mDevelopment properties not configured. Create a .dev_properties.json file first.\x1b[0m');
176
221
  return;
177
222
  }
178
- if (!hasDevPassword) {
223
+ if (!deployAuthReady) {
179
224
  setState('dev-password-input');
180
225
  }
181
226
  else {
@@ -184,8 +229,14 @@ export default function App({ project }) {
184
229
  break;
185
230
  }
186
231
  };
232
+ if (state === 'change-auth-method') {
233
+ return (_jsx(DevPropertiesForm, { projectRoot: project.root, initialProperties: project.devProperties, packageJson: project.packageJson, authOnly: true, onComplete: () => {
234
+ reloadProject();
235
+ setState('menu');
236
+ }, onCancel: () => setState('menu') }));
237
+ }
187
238
  if (state === 'setup') {
188
- return _jsx(SetupFlow, { project: project, onComplete: () => setState('menu') });
239
+ return (_jsx(SetupFlow, { project: project, onReload: reloadProject, onComplete: () => setState('menu') }));
189
240
  }
190
241
  if (state === 'menu') {
191
242
  return _jsx(MainMenu, { project: project, onSelect: handleCommandSelect });
@@ -256,13 +307,13 @@ export default function App({ project }) {
256
307
  if (project.devProperties)
257
308
  project.devProperties.password = undefined;
258
309
  setState('dev-password-input');
259
- } }));
310
+ }, onChangeAuthMethod: () => setState('change-auth-method') }));
260
311
  }
261
312
  if (state === 'setup-signing') {
262
313
  return (_jsx(SigningPropertiesForm, { projectRoot: project.root, onComplete: () => {
263
- // We can't easily update project info here without full reload,
264
- // but since we are just returning to menu, it's fine.
265
- // The user might need to restart CLI or we implement a reload mechanism.
314
+ // Re-detect so the newly written signing credentials are reflected
315
+ // in memory (hasSigningProperties, keychain password) without a restart.
316
+ reloadProject();
266
317
  setState('menu');
267
318
  }, onCancel: () => setState('menu') }));
268
319
  }
package/dist/cli.js CHANGED
@@ -1,22 +1,27 @@
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 os from 'node:os';
8
+ import { runningTasks } from './utils/tasks.js';
9
+ import { killAllChildren } from './utils/process-runner.js';
10
+ import { Shell } from './shell/Shell.js';
8
11
  import { getCommand } from './commands/index.js';
9
- import { requireProject, migrateLegacyPassword, } from './utils/project-detection.js';
12
+ import { requireProject, detectProject, migrateLegacyPassword, } from './utils/project-detection.js';
13
+ import { discoverApps } from './utils/workspace.js';
10
14
  import { promptYesNo } from './utils/password-prompt.js';
11
15
  import { checkForUpdate } from './utils/version-check.js';
12
- import { isFirstRun, markFirstRunComplete, getLastSeenVersion, setLastSeenVersion, } from './utils/config.js';
16
+ import { isFirstRun, markFirstRunComplete, getLastSeenVersion, setLastSeenVersion, getSettings, } from './utils/config.js';
17
+ import { setLanguage } from './utils/i18n.js';
13
18
  import { WelcomeScreen } from './components/WelcomeScreen.js';
14
19
  import { AnimatedLogo } from './components/AnimatedLogo.js';
15
20
  import { printBranding, BIG_LOGO, BIG_LOGO_WIDTH, SMALL_LOGO, SMALL_LOGO_WIDTH, } from './utils/branding.js';
16
21
  const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
17
22
  const cli = meow(`
18
23
  Usage
19
- $ svc Start interactive menu
24
+ $ svc Open the interactive shell (app or workspace)
20
25
  $ svc <command> [options]
21
26
 
22
27
  Commands
@@ -28,11 +33,13 @@ const cli = meow(`
28
33
  info Show project information
29
34
 
30
35
  Options
36
+ --minimal Shell: compact layout for small terminals
31
37
  --help Show this help message
32
38
  --version Show version number
33
39
 
34
40
  Examples
35
- $ svc # Interactive menu
41
+ $ svc # Shell: run inside an app, or at the repo root
42
+ $ svc --minimal # Shell without the sidebar, for a small pane
36
43
  $ svc dev
37
44
  $ svc dev --signed
38
45
  $ svc watch
@@ -58,9 +65,21 @@ const cli = meow(`
58
65
  shortFlag: 'p',
59
66
  default: false,
60
67
  },
68
+ token: {
69
+ type: 'string',
70
+ },
71
+ cookie: {
72
+ type: 'string',
73
+ },
74
+ minimal: {
75
+ type: 'boolean',
76
+ default: false,
77
+ },
61
78
  },
62
79
  });
63
80
  const [commandName, ...args] = cli.input;
81
+ const settings = getSettings();
82
+ setLanguage(settings.language);
64
83
  const CYAN = '\x1b[36m';
65
84
  const BOLD = '\x1b[1m';
66
85
  const DIM = '\x1b[2m';
@@ -89,8 +108,26 @@ function printMasthead(version) {
89
108
  `${spaces(gap)}${DIM}${right}${RESET}${spaces(padding)}${CYAN}│${RESET}`);
90
109
  console.log(`${CYAN}╰${border}╯${RESET}`);
91
110
  }
111
+ /**
112
+ * Stop every running task and kill leftover child processes. In raw mode Ink
113
+ * reads Ctrl+C as a keypress, so no SIGINT reaches anything else. Exits when
114
+ * there was work to stop (or on a signal); otherwise the process ends on its
115
+ * own, so a command's last output is never cut off.
116
+ */
117
+ function shutdown(code) {
118
+ const busy = runningTasks();
119
+ for (const task of busy)
120
+ task.stop();
121
+ const killed = killAllChildren();
122
+ if (busy.length > 0 || killed > 0 || code !== undefined)
123
+ process.exit(code);
124
+ }
125
+ function fail(message, hint) {
126
+ render(_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsxs(Text, { color: "red", children: ["Error: ", message] }), _jsx(Text, { dimColor: true, children: hint })] }));
127
+ process.exit(1);
128
+ }
92
129
  // 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).
130
+ // compact one would wrap.
94
131
  function pickIntroArt(columns) {
95
132
  if (columns >= BIG_LOGO_WIDTH)
96
133
  return BIG_LOGO;
@@ -105,7 +142,34 @@ async function playIntro(art) {
105
142
  app.waitUntilExit().then(() => resolve(), () => resolve());
106
143
  });
107
144
  }
145
+ // Run the full-screen shell on the alternate screen buffer so the scrollback
146
+ // is untouched, and restore it on exit. The animated wordmark plays first,
147
+ // inside the same buffer, when the terminal is wide enough for it.
148
+ async function runShell(apps, workspaceRoot, updatedFrom) {
149
+ process.stdout.write('\x1b[?1049h\x1b[H');
150
+ // Also leave the alternate screen when a signal exits past the finally.
151
+ process.once('exit', () => process.stdout.write('\x1b[?1049l'));
152
+ try {
153
+ const art = process.stdin.isTTY && settings.introAnimation && !cli.flags.minimal
154
+ ? pickIntroArt(process.stdout.columns ?? 0)
155
+ : undefined;
156
+ if (art) {
157
+ await playIntro(art);
158
+ process.stdout.write('\x1b[2J\x1b[H');
159
+ }
160
+ const app = render(_jsx(Shell, { apps: apps, workspaceRoot: workspaceRoot, version: pkg.version, minimal: cli.flags.minimal, updatedFrom: updatedFrom }));
161
+ await app.waitUntilExit();
162
+ }
163
+ finally {
164
+ process.stdout.write('\x1b[?1049l');
165
+ }
166
+ }
108
167
  async function main() {
168
+ for (const signal of ['SIGINT', 'SIGTERM', 'SIGHUP']) {
169
+ process.on(signal, () => {
170
+ shutdown(128 + os.constants.signals[signal]);
171
+ });
172
+ }
109
173
  // On the very first run we show a dedicated welcome screen instead of the
110
174
  // masthead, so the branding is the moment. Only when stdin is a TTY — the
111
175
  // welcome is interactive and would hang in CI / piped input.
@@ -116,19 +180,13 @@ async function main() {
116
180
  // silently rather than claiming an update happened.
117
181
  const lastSeen = getLastSeenVersion();
118
182
  const isUpdate = !firstRun && lastSeen !== undefined && lastSeen !== pkg.version;
119
- // On the plain interactive `svc` (no command), play the animated wordmark
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;
126
183
  if (!firstRun) {
127
- if (isUpdate) {
184
+ // The shell shows the changelog itself; only direct commands get a banner.
185
+ if (isUpdate && commandName) {
128
186
  printBranding();
129
187
  console.log(`\x1b[32m\n ✨ Updated to v${pkg.version}\x1b[0m \x1b[2m(from v${lastSeen})\x1b[0m\n`);
130
188
  }
131
- else if (!introArt) {
189
+ else if (commandName) {
132
190
  printMasthead(pkg.version);
133
191
  }
134
192
  // Record the current version so the banner shows once per upgrade.
@@ -139,36 +197,63 @@ async function main() {
139
197
  console.log(`\x1b[33m ↑ update available: ${pkg.version} → ${latestVersion} (run: npm i -g ${pkg.name})\x1b[0m`);
140
198
  }
141
199
  }
200
+ // No command: the shell. Inside an app it is single-app mode; anywhere
201
+ // above one or more apps it is workspace mode.
202
+ if (!commandName) {
203
+ let project = null;
204
+ try {
205
+ project = detectProject();
206
+ }
207
+ catch (error) {
208
+ fail(error.message, 'Fix the manifest and try again');
209
+ }
210
+ if (!project) {
211
+ const apps = discoverApps(process.cwd());
212
+ if (apps.length === 0) {
213
+ fail('No Sitevision apps found here.', 'Run svc inside an app directory (manifest.json) or at the root of a repo that contains apps.');
214
+ }
215
+ await runShell(apps, process.cwd(), isUpdate ? lastSeen : undefined);
216
+ shutdown();
217
+ return;
218
+ }
219
+ if (firstRun) {
220
+ await new Promise(resolve => {
221
+ const app = render(_jsx(WelcomeScreen, { project: project, onComplete: () => {
222
+ markFirstRunComplete();
223
+ setLastSeenVersion(pkg.version);
224
+ app.unmount();
225
+ } }));
226
+ app.waitUntilExit().then(() => resolve(), () => resolve());
227
+ });
228
+ }
229
+ await runShell([project], undefined, isUpdate ? lastSeen : undefined);
230
+ shutdown();
231
+ return;
232
+ }
142
233
  // Check if we're in a Sitevision project
143
234
  const project = (() => {
144
235
  try {
145
236
  return requireProject();
146
237
  }
147
238
  catch (error) {
148
- 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" })] }));
149
- process.exit(1);
239
+ return fail(error.message, "Make sure you're in a Sitevision project directory");
150
240
  }
151
241
  })();
152
- // First run: show the welcome (branding + optional signing-password save),
153
- // then continue to the normal flow once the user dismisses it.
154
- if (firstRun) {
155
- await new Promise(resolve => {
156
- const app = render(_jsx(WelcomeScreen, { project: project, onComplete: () => {
157
- markFirstRunComplete();
158
- setLastSeenVersion(pkg.version);
159
- app.unmount();
160
- } }));
161
- app.waitUntilExit().then(() => resolve(), () => resolve());
162
- });
163
- }
164
- // If no command, show interactive menu (with the animated intro first when
165
- // the terminal can fit it).
166
- if (!commandName) {
167
- if (introArt) {
168
- await playIntro(introArt);
242
+ // --token / --cookie override the resolved bearer token / session cookie for
243
+ // this run (manual / CI path, alongside SITEVISION_ACCESS_TOKEN and
244
+ // SITEVISION_SESSION_COOKIE).
245
+ if (cli.flags.token || cli.flags.cookie) {
246
+ if (project.devProperties) {
247
+ if (cli.flags.token) {
248
+ project.devProperties.accessToken = cli.flags.token;
249
+ }
250
+ if (cli.flags.cookie) {
251
+ project.devProperties.sessionCookie = cli.flags.cookie;
252
+ }
253
+ }
254
+ else {
255
+ console.log('\x1b[33m--token/--cookie needs a .dev_properties.json (domain, site, addon) to deploy against.\x1b[0m');
169
256
  }
170
- render(_jsx(App, { project: project }));
171
- return;
172
257
  }
173
258
  // Get the command
174
259
  const command = getCommand(commandName);
@@ -177,9 +262,8 @@ async function main() {
177
262
  process.exit(1);
178
263
  }
179
264
  // Offer to migrate a legacy plaintext password into the OS keychain.
180
- // Interactive `svc` handles this in SetupFlow; this covers direct commands
181
- // (svc deploy/dev/sign/…). Skip on non-TTY stdin (e.g. CI) where prompting
182
- // would fail — the plaintext password is still used for this run.
265
+ // Skip on non-TTY stdin (e.g. CI) where prompting would fail — the
266
+ // plaintext password is still used for this run.
183
267
  if (project.hasLegacyPassword && process.stdin.isTTY) {
184
268
  console.log('\n\x1b[33m⚠ Plaintext password found in .dev_properties.json\x1b[0m');
185
269
  const move = await promptYesNo('Move it to the OS keychain and remove it from the file? (y/N): ');
@@ -198,6 +282,7 @@ async function main() {
198
282
  flags: cli.flags,
199
283
  args,
200
284
  });
285
+ shutdown();
201
286
  }
202
287
  main().catch(error => {
203
288
  console.error('Fatal error:', error);
@@ -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();
@@ -8,10 +8,10 @@ interface DeployScreenProps {
8
8
  force: boolean;
9
9
  production: boolean;
10
10
  activate: boolean;
11
- signingPassword?: string;
12
11
  onBack?: () => void;
13
12
  onRetryCredentials?: () => void;
13
+ onChangeAuthMethod?: () => void;
14
14
  }
15
- export declare function DeployScreen({ projectRoot, manifest, devProperties, force, production, activate, signingPassword, onBack, onRetryCredentials, }: DeployScreenProps): React.JSX.Element;
15
+ export declare function DeployScreen({ projectRoot, manifest, devProperties, force, production, activate, onBack, onRetryCredentials, onChangeAuthMethod, }: DeployScreenProps): React.JSX.Element;
16
16
  export declare const deployCommand: Command;
17
17
  export {};