sitevision-cli 1.0.0-beta.2 → 1.0.0-beta.21
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.d.ts +1 -1
- package/dist/app.js +59 -8
- package/dist/cli.js +96 -39
- package/dist/commands/build.js +1 -1
- package/dist/commands/deploy.d.ts +2 -2
- package/dist/commands/deploy.js +135 -25
- package/dist/commands/dev.d.ts +8 -10
- package/dist/commands/dev.js +77 -366
- package/dist/commands/info.js +2 -2
- package/dist/commands/watch.js +5 -23
- package/dist/components/AnimatedLogo.js +8 -2
- package/dist/components/AuthLoginScreen.d.ts +21 -0
- package/dist/components/AuthLoginScreen.js +90 -0
- package/dist/components/DevPropertiesForm.d.ts +2 -1
- package/dist/components/DevPropertiesForm.js +198 -33
- package/dist/components/InfoScreen.js +2 -2
- package/dist/components/MainMenu.js +7 -2
- package/dist/components/PasswordInput.js +2 -1
- package/dist/components/SetupFlow.d.ts +2 -1
- package/dist/components/SetupFlow.js +100 -11
- package/dist/shell/AddonPicker.d.ts +14 -0
- package/dist/shell/AddonPicker.js +54 -0
- package/dist/shell/CommandPalette.d.ts +8 -0
- package/dist/shell/CommandPalette.js +63 -0
- package/dist/shell/ConfigForm.d.ts +36 -0
- package/dist/shell/ConfigForm.js +558 -0
- package/dist/shell/Frame.d.ts +59 -0
- package/dist/shell/Frame.js +134 -0
- package/dist/shell/Settings.d.ts +6 -0
- package/dist/shell/Settings.js +96 -0
- package/dist/shell/Shell.d.ts +9 -0
- package/dist/shell/Shell.js +586 -0
- package/dist/shell/Tabs.d.ts +36 -0
- package/dist/shell/Tabs.js +90 -0
- package/dist/shell/actions.d.ts +45 -0
- package/dist/shell/actions.js +0 -0
- package/dist/types/index.d.ts +44 -5
- package/dist/utils/config.d.ts +10 -0
- package/dist/utils/config.js +14 -0
- package/dist/utils/environments.d.ts +20 -0
- package/dist/utils/environments.js +74 -0
- package/dist/utils/i18n.d.ts +12 -0
- package/dist/utils/i18n.js +279 -0
- package/dist/utils/jsonc.d.ts +19 -0
- package/dist/utils/jsonc.js +74 -0
- package/dist/utils/keychain.d.ts +9 -0
- package/dist/utils/keychain.js +54 -0
- package/dist/utils/oauth2-auth.d.ts +64 -0
- package/dist/utils/oauth2-auth.js +242 -0
- package/dist/utils/password-prompt.d.ts +5 -0
- package/dist/utils/password-prompt.js +28 -0
- package/dist/utils/project-detection.d.ts +105 -6
- package/dist/utils/project-detection.js +411 -54
- package/dist/utils/session-cookie-auth.d.ts +35 -0
- package/dist/utils/session-cookie-auth.js +99 -0
- package/dist/utils/sitevision-api.d.ts +64 -5
- package/dist/utils/sitevision-api.js +195 -33
- package/dist/utils/tasks.d.ts +48 -0
- package/dist/utils/tasks.js +371 -0
- package/dist/utils/workspace.d.ts +17 -0
- package/dist/utils/workspace.js +67 -0
- package/package.json +3 -1
- package/readme.md +102 -121
package/dist/commands/dev.d.ts
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { type Command } from './types.js';
|
|
3
|
-
import
|
|
3
|
+
import { type DevOptions } from '../utils/tasks.js';
|
|
4
|
+
import type { ProjectInfo, SigningCredentials } from '../types/index.js';
|
|
4
5
|
interface DevScreenProps {
|
|
5
|
-
|
|
6
|
-
|
|
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
|
-
|
|
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 {};
|
package/dist/commands/dev.js
CHANGED
|
@@ -1,359 +1,66 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import fs from 'fs';
|
|
3
|
-
import path from 'path';
|
|
4
2
|
import React from 'react';
|
|
5
|
-
import { render, Box, Text, useApp, useInput } from 'ink';
|
|
3
|
+
import { render, Box, Text, useApp, useInput, useStdout } from 'ink';
|
|
6
4
|
import { StatusIndicator } from '../components/StatusIndicator.js';
|
|
7
|
-
import { WebpackRunner, hasLocalWebpackConfig } from '../utils/webpack-runner.js';
|
|
8
|
-
import { hasSitevisionScripts, runSitevisionScriptsBuild, getDelegatedZipPath, checkSitevisionScriptsCompatibility, } from '../utils/sitevision-scripts-runner.js';
|
|
9
5
|
import { promptPassword, promptYesNo } from '../utils/password-prompt.js';
|
|
10
|
-
import { signApp, deployApp } from '../utils/sitevision-api.js';
|
|
11
6
|
import { setDeployPassword } from '../utils/keychain.js';
|
|
12
7
|
import { resolveSigningPassword } from '../utils/signing-password.js';
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
|
|
8
|
+
import { startDev, useTasks } from '../utils/tasks.js';
|
|
9
|
+
import { Log } from '../shell/Tabs.js';
|
|
10
|
+
/** Standalone `svc dev` / `svc watch`: one task, its log, Ctrl+C or q to stop. */
|
|
11
|
+
export function DevScreen({ project, options }) {
|
|
16
12
|
const { exit } = useApp();
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
});
|
|
13
|
+
const { stdout } = useStdout();
|
|
14
|
+
const tasks = useTasks();
|
|
15
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
16
|
+
const task = React.useMemo(() => startDev(project, options), []);
|
|
17
|
+
const live = tasks.find(t => t.id === task.id) ?? task;
|
|
23
18
|
useInput((input, key) => {
|
|
24
|
-
if (
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (onRetryCredentials && state.status === 'error' && input === 'r') {
|
|
28
|
-
onRetryCredentials();
|
|
19
|
+
if (key.escape || input === 'q') {
|
|
20
|
+
live.stop();
|
|
21
|
+
exit();
|
|
29
22
|
}
|
|
30
23
|
});
|
|
31
|
-
const webpackRunnerRef = React.useRef(null);
|
|
32
|
-
const watchersRef = React.useRef([]);
|
|
33
|
-
const debounceTimerRef = React.useRef(null);
|
|
34
|
-
const isBuildingRef = React.useRef(false);
|
|
35
|
-
const pendingRebuildRef = React.useRef(false);
|
|
36
|
-
// Sign (if needed) and deploy an already-built zip, updating UI state.
|
|
37
|
-
const signAndDeploy = React.useCallback(async (zipPath, buildTime) => {
|
|
38
|
-
try {
|
|
39
|
-
let deployZipPath = zipPath;
|
|
40
|
-
// Sign if needed
|
|
41
|
-
if (signed && signingCredentials) {
|
|
42
|
-
setState(prev => ({
|
|
43
|
-
...prev,
|
|
44
|
-
status: 'signing',
|
|
45
|
-
message: 'Signing app...',
|
|
46
|
-
}));
|
|
47
|
-
const signedZipPath = getSignedZipPath(projectRoot, manifest);
|
|
48
|
-
const signResult = await signApp(zipPath, signingCredentials, signedZipPath);
|
|
49
|
-
if (!signResult.success) {
|
|
50
|
-
setState(prev => ({
|
|
51
|
-
...prev,
|
|
52
|
-
status: 'error',
|
|
53
|
-
message: `Signing failed: ${signResult.error}`,
|
|
54
|
-
error: signResult.error,
|
|
55
|
-
}));
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
deployZipPath = signedZipPath;
|
|
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
|
-
}
|
|
74
|
-
// Deploy
|
|
75
|
-
setState(prev => ({
|
|
76
|
-
...prev,
|
|
77
|
-
status: 'deploying',
|
|
78
|
-
message: 'Deploying to dev...',
|
|
79
|
-
}));
|
|
80
|
-
const appType = getAppType(manifest);
|
|
81
|
-
const deployResult = await deployApp(deployZipPath, {
|
|
82
|
-
domain: devProperties.domain,
|
|
83
|
-
siteName: devProperties.siteName,
|
|
84
|
-
addonName: devProperties.addonName,
|
|
85
|
-
username: devProperties.username,
|
|
86
|
-
password: devProperties.password,
|
|
87
|
-
useHTTP: devProperties.useHTTPForDevDeploy,
|
|
88
|
-
}, appType, true);
|
|
89
|
-
if (!deployResult.success) {
|
|
90
|
-
setState(prev => ({
|
|
91
|
-
...prev,
|
|
92
|
-
status: 'error',
|
|
93
|
-
message: `Deploy failed: ${deployResult.error}`,
|
|
94
|
-
error: deployResult.error,
|
|
95
|
-
}));
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
// Success - back to watching
|
|
99
|
-
setState(prev => ({
|
|
100
|
-
...prev,
|
|
101
|
-
status: 'ready',
|
|
102
|
-
message: 'Deployed. Watching for changes...',
|
|
103
|
-
buildCount: prev.buildCount + 1,
|
|
104
|
-
lastBuildTime: buildTime,
|
|
105
|
-
error: undefined,
|
|
106
|
-
}));
|
|
107
|
-
}
|
|
108
|
-
catch (error) {
|
|
109
|
-
setState(prev => ({
|
|
110
|
-
...prev,
|
|
111
|
-
status: 'error',
|
|
112
|
-
message: error instanceof Error ? error.message : String(error),
|
|
113
|
-
error: error instanceof Error ? error.message : String(error),
|
|
114
|
-
}));
|
|
115
|
-
}
|
|
116
|
-
}, [projectRoot, manifest, devProperties, signed, deploy, signingCredentials]);
|
|
117
|
-
// In-house webpack path: copy static, zip, then sign + deploy.
|
|
118
|
-
const handleBuildComplete = React.useCallback(async (result) => {
|
|
119
|
-
if (!result.success) {
|
|
120
|
-
setState(prev => ({
|
|
121
|
-
...prev,
|
|
122
|
-
status: 'error',
|
|
123
|
-
message: result.errors?.join('\n') || 'Build failed',
|
|
124
|
-
error: result.errors?.join('\n'),
|
|
125
|
-
}));
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
try {
|
|
129
|
-
copyStaticToBuild(projectRoot);
|
|
130
|
-
const appId = getFullAppId(manifest.id);
|
|
131
|
-
await createBuildZip(projectRoot, appId);
|
|
132
|
-
await signAndDeploy(getZipPath(projectRoot, manifest), result.stats?.time);
|
|
133
|
-
}
|
|
134
|
-
catch (error) {
|
|
135
|
-
setState(prev => ({
|
|
136
|
-
...prev,
|
|
137
|
-
status: 'error',
|
|
138
|
-
message: error instanceof Error ? error.message : String(error),
|
|
139
|
-
error: error instanceof Error ? error.message : String(error),
|
|
140
|
-
}));
|
|
141
|
-
}
|
|
142
|
-
}, [projectRoot, manifest, signAndDeploy]);
|
|
143
|
-
// Delegated path: full `sitevision-scripts build` then sign + deploy.
|
|
144
|
-
// Coalesces overlapping triggers so a save mid-build queues one rebuild.
|
|
145
|
-
const runDelegatedBuild = React.useCallback(async () => {
|
|
146
|
-
if (isBuildingRef.current) {
|
|
147
|
-
pendingRebuildRef.current = true;
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
isBuildingRef.current = true;
|
|
151
|
-
const buildOnce = async () => {
|
|
152
|
-
pendingRebuildRef.current = false;
|
|
153
|
-
setState(prev => ({
|
|
154
|
-
...prev,
|
|
155
|
-
status: 'building',
|
|
156
|
-
message: 'Building via sitevision-scripts...',
|
|
157
|
-
}));
|
|
158
|
-
const result = await runSitevisionScriptsBuild(projectRoot);
|
|
159
|
-
if (result.success) {
|
|
160
|
-
await signAndDeploy(getDelegatedZipPath(projectRoot, manifest.id));
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
setState(prev => ({
|
|
164
|
-
...prev,
|
|
165
|
-
status: 'error',
|
|
166
|
-
message: result.error ?? 'Build failed',
|
|
167
|
-
error: `${result.error}\n${result.output.slice(-1000)}`,
|
|
168
|
-
}));
|
|
169
|
-
}
|
|
170
|
-
if (pendingRebuildRef.current) {
|
|
171
|
-
await buildOnce();
|
|
172
|
-
}
|
|
173
|
-
};
|
|
174
|
-
try {
|
|
175
|
-
await buildOnce();
|
|
176
|
-
}
|
|
177
|
-
finally {
|
|
178
|
-
isBuildingRef.current = false;
|
|
179
|
-
}
|
|
180
|
-
}, [projectRoot, manifest, signAndDeploy]);
|
|
181
|
-
// Watch source files and trigger a delegated rebuild (debounced).
|
|
182
|
-
const startFileWatcher = React.useCallback(() => {
|
|
183
|
-
const targets = [
|
|
184
|
-
'src',
|
|
185
|
-
'static',
|
|
186
|
-
'i18n',
|
|
187
|
-
'resource',
|
|
188
|
-
'config',
|
|
189
|
-
'manifest.json',
|
|
190
|
-
]
|
|
191
|
-
.map(name => path.join(projectRoot, name))
|
|
192
|
-
.filter(target => fs.existsSync(target));
|
|
193
|
-
for (const target of targets) {
|
|
194
|
-
const isDir = fs.statSync(target).isDirectory();
|
|
195
|
-
const watcher = fs.watch(target, { recursive: isDir }, () => {
|
|
196
|
-
if (debounceTimerRef.current) {
|
|
197
|
-
clearTimeout(debounceTimerRef.current);
|
|
198
|
-
}
|
|
199
|
-
debounceTimerRef.current = setTimeout(() => {
|
|
200
|
-
void runDelegatedBuild();
|
|
201
|
-
}, 300);
|
|
202
|
-
});
|
|
203
|
-
watchersRef.current.push(watcher);
|
|
204
|
-
}
|
|
205
|
-
}, [projectRoot, runDelegatedBuild]);
|
|
206
24
|
React.useEffect(() => {
|
|
207
|
-
const
|
|
208
|
-
|
|
209
|
-
try {
|
|
210
|
-
// Clean build directory
|
|
211
|
-
cleanBuild(projectRoot);
|
|
212
|
-
if (isBundled && !hasLocalWebpackConfig(projectRoot)) {
|
|
213
|
-
// No local webpack config: delegate each build to
|
|
214
|
-
// sitevision-scripts (full rebuild) and watch source files
|
|
215
|
-
// ourselves, keeping the CLI's own sign + deploy flow.
|
|
216
|
-
if (!hasSitevisionScripts(projectRoot)) {
|
|
217
|
-
setState({
|
|
218
|
-
status: 'error',
|
|
219
|
-
message: 'No webpack.config.js found and @sitevision/sitevision-scripts is not installed. Run npm install.',
|
|
220
|
-
buildCount: 0,
|
|
221
|
-
webpackReady: false,
|
|
222
|
-
error: 'No build pipeline available',
|
|
223
|
-
});
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
const warning = checkSitevisionScriptsCompatibility(projectRoot).warning;
|
|
227
|
-
setState(prev => ({ ...prev, webpackReady: true, warning }));
|
|
228
|
-
startFileWatcher();
|
|
229
|
-
await runDelegatedBuild();
|
|
230
|
-
}
|
|
231
|
-
else if (isBundled) {
|
|
232
|
-
// Project ships its own webpack config: incremental in-process watch.
|
|
233
|
-
if (!WebpackRunner.isWebpackAvailable(projectRoot)) {
|
|
234
|
-
setState({
|
|
235
|
-
status: 'error',
|
|
236
|
-
message: 'webpack not found. Run npm install.',
|
|
237
|
-
buildCount: 0,
|
|
238
|
-
webpackReady: false,
|
|
239
|
-
error: 'webpack not found',
|
|
240
|
-
});
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
setState(prev => ({
|
|
244
|
-
...prev,
|
|
245
|
-
status: 'building',
|
|
246
|
-
message: 'Starting initial build...',
|
|
247
|
-
}));
|
|
248
|
-
const appType = getAppType(manifest);
|
|
249
|
-
const runner = new WebpackRunner(projectRoot, {
|
|
250
|
-
mode: 'development',
|
|
251
|
-
watch: true,
|
|
252
|
-
cssPrefix: manifest.id,
|
|
253
|
-
restApp: appType === 'rest',
|
|
254
|
-
});
|
|
255
|
-
webpackRunnerRef.current = runner;
|
|
256
|
-
await runner.watch(handleBuildComplete);
|
|
257
|
-
setState(prev => ({
|
|
258
|
-
...prev,
|
|
259
|
-
status: 'watching',
|
|
260
|
-
message: 'Building...',
|
|
261
|
-
webpackReady: true,
|
|
262
|
-
}));
|
|
263
|
-
}
|
|
264
|
-
else {
|
|
265
|
-
// Non-bundled app: just copy and deploy
|
|
266
|
-
setState(prev => ({
|
|
267
|
-
...prev,
|
|
268
|
-
status: 'building',
|
|
269
|
-
message: 'Copying files...',
|
|
270
|
-
}));
|
|
271
|
-
await handleBuildComplete({
|
|
272
|
-
success: true,
|
|
273
|
-
stats: { time: 0, hash: '', assets: [] },
|
|
274
|
-
});
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
catch (error) {
|
|
278
|
-
setState({
|
|
279
|
-
status: 'error',
|
|
280
|
-
message: error instanceof Error ? error.message : String(error),
|
|
281
|
-
buildCount: 0,
|
|
282
|
-
webpackReady: false,
|
|
283
|
-
error: error instanceof Error ? error.message : String(error),
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
startWatch();
|
|
288
|
-
// Cleanup
|
|
289
|
-
return () => {
|
|
290
|
-
if (webpackRunnerRef.current) {
|
|
291
|
-
webpackRunnerRef.current.close().catch(() => { });
|
|
292
|
-
}
|
|
293
|
-
if (debounceTimerRef.current) {
|
|
294
|
-
clearTimeout(debounceTimerRef.current);
|
|
295
|
-
}
|
|
296
|
-
for (const watcher of watchersRef.current) {
|
|
297
|
-
watcher.close();
|
|
298
|
-
}
|
|
299
|
-
watchersRef.current = [];
|
|
300
|
-
};
|
|
301
|
-
}, [
|
|
302
|
-
projectRoot,
|
|
303
|
-
manifest,
|
|
304
|
-
handleBuildComplete,
|
|
305
|
-
runDelegatedBuild,
|
|
306
|
-
startFileWatcher,
|
|
307
|
-
]);
|
|
308
|
-
// Handle Ctrl+C
|
|
309
|
-
React.useEffect(() => {
|
|
310
|
-
const handleExit = () => {
|
|
311
|
-
if (webpackRunnerRef.current) {
|
|
312
|
-
webpackRunnerRef.current.close().catch(() => { });
|
|
313
|
-
}
|
|
314
|
-
for (const watcher of watchersRef.current) {
|
|
315
|
-
watcher.close();
|
|
316
|
-
}
|
|
25
|
+
const stop = () => {
|
|
26
|
+
live.stop();
|
|
317
27
|
exit();
|
|
318
28
|
};
|
|
319
|
-
process.on('SIGINT',
|
|
320
|
-
process.on('SIGTERM',
|
|
29
|
+
process.on('SIGINT', stop);
|
|
30
|
+
process.on('SIGTERM', stop);
|
|
321
31
|
return () => {
|
|
322
|
-
process.off('SIGINT',
|
|
323
|
-
process.off('SIGTERM',
|
|
32
|
+
process.off('SIGINT', stop);
|
|
33
|
+
process.off('SIGTERM', stop);
|
|
324
34
|
};
|
|
325
|
-
}, [exit]);
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
35
|
+
}, [live, exit]);
|
|
36
|
+
const status = live.status === 'running'
|
|
37
|
+
? live.phase === 'error'
|
|
38
|
+
? 'error'
|
|
39
|
+
: 'running'
|
|
40
|
+
: live.status === 'success'
|
|
41
|
+
? 'success'
|
|
42
|
+
: 'error';
|
|
43
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(StatusIndicator, { status: status, label: live.phase, message: `${live.label} ${live.appName}` }), _jsx(Box, { marginTop: 1, children: _jsx(Log, { task: live, height: (stdout.rows || 24) - 6, scroll: 0, wrap: true }) }), _jsx(Text, { dimColor: true, children: "Press q, Esc or Ctrl+C to stop" })] }));
|
|
44
|
+
}
|
|
45
|
+
/** Resolve signing credentials for signed dev/watch, prompting if needed. */
|
|
46
|
+
export async function resolveSigningForCli(project) {
|
|
47
|
+
if (!project.hasSigningProperties ||
|
|
48
|
+
!project.devProperties?.signingUsername) {
|
|
49
|
+
console.log('\n\x1b[33mSigning credentials not configured.\x1b[0m');
|
|
50
|
+
console.log('Run \x1b[36msetup-signing\x1b[0m to configure credentials.\n');
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
const signingUsername = project.devProperties.signingUsername;
|
|
54
|
+
const password = await resolveSigningPassword(signingUsername);
|
|
55
|
+
if (!password) {
|
|
56
|
+
console.log('\x1b[31mError: Password is required for signed mode\x1b[0m');
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
username: signingUsername,
|
|
61
|
+
password,
|
|
62
|
+
certificateName: project.devProperties.certificateName,
|
|
353
63
|
};
|
|
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
|
|
355
|
-
? ` | Last build: ${state.lastBuildTime}ms`
|
|
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" }))] })] }));
|
|
357
64
|
}
|
|
358
65
|
export const devCommand = {
|
|
359
66
|
name: 'dev',
|
|
@@ -368,15 +75,22 @@ export const devCommand = {
|
|
|
368
75
|
},
|
|
369
76
|
},
|
|
370
77
|
async execute({ project, flags }) {
|
|
371
|
-
|
|
372
|
-
if (!project.hasDevProperties || !
|
|
78
|
+
const dev = project.devProperties;
|
|
79
|
+
if (!project.hasDevProperties || !dev) {
|
|
373
80
|
console.log('\n\x1b[33mDeployment credentials not configured.\x1b[0m');
|
|
374
81
|
console.log('Create a .dev_properties.json file with domain, siteName, addonName, and username, then run setup.\n');
|
|
375
82
|
return;
|
|
376
83
|
}
|
|
377
|
-
//
|
|
378
|
-
|
|
379
|
-
|
|
84
|
+
// The standalone command only prompts for a basic password; OAuth2/cookie
|
|
85
|
+
// logins are interactive and live in the shell (`svc`) or `svc deploy`.
|
|
86
|
+
if ((dev.authMethod ?? 'basic') !== 'basic' &&
|
|
87
|
+
!dev.accessToken &&
|
|
88
|
+
!dev.sessionCookie) {
|
|
89
|
+
console.log('\n\x1b[33mNo token/cookie available. Run `svc` and use Dev from the shell, or set SITEVISION_ACCESS_TOKEN / SITEVISION_SESSION_COOKIE.\x1b[0m\n');
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if ((dev.authMethod ?? 'basic') === 'basic' && !dev.password) {
|
|
93
|
+
const { domain, username } = dev;
|
|
380
94
|
console.log('');
|
|
381
95
|
const pw = await promptPassword(`Deploy password for ${username}@${domain}: `);
|
|
382
96
|
if (!pw) {
|
|
@@ -387,31 +101,28 @@ export const devCommand = {
|
|
|
387
101
|
if (remember && domain && username) {
|
|
388
102
|
setDeployPassword(domain, username, pw);
|
|
389
103
|
}
|
|
390
|
-
|
|
104
|
+
dev.password = pw;
|
|
391
105
|
}
|
|
392
|
-
const signed = Boolean(flags['signed']);
|
|
393
106
|
let signingCredentials;
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
if (!
|
|
397
|
-
!project.devProperties.signingUsername) {
|
|
398
|
-
console.log('\n\x1b[33mSigning credentials not configured.\x1b[0m');
|
|
399
|
-
console.log('Run \x1b[36msetup-signing\x1b[0m to configure credentials.\n');
|
|
107
|
+
if (flags['signed']) {
|
|
108
|
+
signingCredentials = await resolveSigningForCli(project);
|
|
109
|
+
if (!signingCredentials)
|
|
400
110
|
return;
|
|
401
|
-
}
|
|
402
|
-
const signingUsername = project.devProperties.signingUsername;
|
|
403
|
-
const password = await resolveSigningPassword(signingUsername);
|
|
404
|
-
if (!password) {
|
|
405
|
-
console.log('\x1b[31mError: Password is required for signed mode\x1b[0m');
|
|
406
|
-
return;
|
|
407
|
-
}
|
|
408
|
-
signingCredentials = {
|
|
409
|
-
username: signingUsername,
|
|
410
|
-
password,
|
|
411
|
-
certificateName: project.devProperties.certificateName,
|
|
412
|
-
};
|
|
413
111
|
}
|
|
414
|
-
const { waitUntilExit } = render(_jsx(DevScreen, {
|
|
112
|
+
const { waitUntilExit } = render(_jsx(DevScreen, { project: project, options: {
|
|
113
|
+
deploy: true,
|
|
114
|
+
signingCredentials,
|
|
115
|
+
deployConfig: {
|
|
116
|
+
domain: dev.domain,
|
|
117
|
+
siteName: dev.siteName,
|
|
118
|
+
addonName: dev.addonName,
|
|
119
|
+
username: dev.username,
|
|
120
|
+
password: dev.password,
|
|
121
|
+
accessToken: dev.accessToken,
|
|
122
|
+
sessionCookie: dev.sessionCookie,
|
|
123
|
+
useHTTP: dev.useHTTPForDevDeploy,
|
|
124
|
+
},
|
|
125
|
+
} }));
|
|
415
126
|
await waitUntilExit();
|
|
416
127
|
},
|
|
417
128
|
};
|
package/dist/commands/info.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { render } from 'ink';
|
|
3
3
|
import { Box, Text } from 'ink';
|
|
4
|
-
import { getAppType } from '../utils/project-detection.js';
|
|
4
|
+
import { getAppType, localizedText } from '../utils/project-detection.js';
|
|
5
5
|
function InfoScreen({ project }) {
|
|
6
6
|
const appType = getAppType(project.manifest);
|
|
7
|
-
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "Sitevision Project Information" }) }), _jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Name: " }), _jsx(Text, { children: project.manifest.name })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "ID: " }), _jsx(Text, { children: project.manifest.id })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Version: " }), _jsx(Text, { children: project.manifest.version })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Type: " }), _jsx(Text, { color: "green", children: project.manifest.type }), _jsxs(Text, { dimColor: true, children: [" (", appType, ")"] })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Bundled: " }), _jsx(Text, { children: project.manifest.bundled ? 'Yes' : 'No' })] })] }), project.hasDevProperties && project.devProperties && (_jsxs(_Fragment, { children: [_jsx(Box, { marginTop: 1, marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "Development Configuration" }) }), _jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Domain: " }), _jsx(Text, { children: project.devProperties.domain })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Site: " }), _jsx(Text, { children: project.devProperties.siteName })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Addon: " }), _jsx(Text, { children: project.devProperties.addonName })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Username: " }), _jsx(Text, { children: project.devProperties.username })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Use HTTP: " }), _jsx(Text, { children: project.devProperties.useHTTPForDevDeploy ? 'Yes' : 'No' })] })] })] })), !project.hasDevProperties && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "yellow", children: ["\u26A0 No dev properties found. Run", ' ', _jsx(Text, { bold: true, children: "setup-dev-properties" }), " to configure."] }) })), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { bold: true, children: "Project Root: " }), _jsx(Text, { dimColor: true, children: project.root })] })] }));
|
|
7
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "Sitevision Project Information" }) }), _jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Name: " }), _jsx(Text, { children: localizedText(project.manifest.name) })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "ID: " }), _jsx(Text, { children: project.manifest.id })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Version: " }), _jsx(Text, { children: project.manifest.version })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Type: " }), _jsx(Text, { color: "green", children: project.manifest.type }), _jsxs(Text, { dimColor: true, children: [" (", appType, ")"] })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Bundled: " }), _jsx(Text, { children: project.manifest.bundled ? 'Yes' : 'No' })] })] }), project.hasDevProperties && project.devProperties && (_jsxs(_Fragment, { children: [_jsx(Box, { marginTop: 1, marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "Development Configuration" }) }), _jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Domain: " }), _jsx(Text, { children: project.devProperties.domain })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Site: " }), _jsx(Text, { children: project.devProperties.siteName })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Addon: " }), _jsx(Text, { children: project.devProperties.addonName })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Username: " }), _jsx(Text, { children: project.devProperties.username })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Use HTTP: " }), _jsx(Text, { children: project.devProperties.useHTTPForDevDeploy ? 'Yes' : 'No' })] })] })] })), !project.hasDevProperties && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "yellow", children: ["\u26A0 No dev properties found. Run", ' ', _jsx(Text, { bold: true, children: "setup-dev-properties" }), " to configure."] }) })), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { bold: true, children: "Project Root: " }), _jsx(Text, { dimColor: true, children: project.root })] })] }));
|
|
8
8
|
}
|
|
9
9
|
export const infoCommand = {
|
|
10
10
|
name: 'info',
|
package/dist/commands/watch.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { render } from 'ink';
|
|
3
|
-
import { DevScreen } from './dev.js';
|
|
4
|
-
import { resolveSigningPassword } from '../utils/signing-password.js';
|
|
3
|
+
import { DevScreen, resolveSigningForCli } from './dev.js';
|
|
5
4
|
export const watchCommand = {
|
|
6
5
|
name: 'watch',
|
|
7
6
|
description: 'Watch and rebuild (optionally signing) without deploying',
|
|
@@ -15,30 +14,13 @@ export const watchCommand = {
|
|
|
15
14
|
},
|
|
16
15
|
},
|
|
17
16
|
async execute({ project, flags }) {
|
|
18
|
-
const signed = Boolean(flags['signed']);
|
|
19
17
|
let signingCredentials;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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');
|
|
18
|
+
if (flags['signed']) {
|
|
19
|
+
signingCredentials = await resolveSigningForCli(project);
|
|
20
|
+
if (!signingCredentials)
|
|
27
21
|
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
22
|
}
|
|
41
|
-
const { waitUntilExit } = render(_jsx(DevScreen, {
|
|
23
|
+
const { waitUntilExit } = render(_jsx(DevScreen, { project: project, options: { deploy: false, signingCredentials } }));
|
|
42
24
|
await waitUntilExit();
|
|
43
25
|
},
|
|
44
26
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Fragment, useEffect, useRef, useState } from 'react';
|
|
3
|
-
import { Box, Text } from 'ink';
|
|
3
|
+
import { Box, Text, useStdout } from 'ink';
|
|
4
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
|
|
@@ -83,5 +83,11 @@ export function AnimatedLogo({ art = BIG_LOGO, onDone }) {
|
|
|
83
83
|
}
|
|
84
84
|
}, [frame, total, onDone]);
|
|
85
85
|
const edge = (frame + 1) * SWEEP_COLS_PER_FRAME;
|
|
86
|
-
|
|
86
|
+
// Centre the wordmark on the alternate screen. `rows - 1` leaves room for
|
|
87
|
+
// Ink's trailing newline; a terminal too short for the art just renders it
|
|
88
|
+
// top-aligned rather than scrolling.
|
|
89
|
+
const { stdout } = useStdout();
|
|
90
|
+
const height = (stdout.rows || 24) - 1;
|
|
91
|
+
const fits = height >= art.length + 2;
|
|
92
|
+
return (_jsx(Box, { width: stdout.columns || 80, height: fits ? height : undefined, alignItems: "center", justifyContent: "center", children: _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 })] })] }) }));
|
|
87
93
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { DevProperties } from '../types/index.js';
|
|
3
|
+
interface Credential {
|
|
4
|
+
accessToken?: string;
|
|
5
|
+
sessionCookie?: string;
|
|
6
|
+
}
|
|
7
|
+
interface Props {
|
|
8
|
+
method: 'oauth2' | 'cookie';
|
|
9
|
+
devProperties: DevProperties;
|
|
10
|
+
onComplete: (credential: Credential) => void;
|
|
11
|
+
onError: (message: string) => void;
|
|
12
|
+
onCancel: () => void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Ink-native interactive login for OAuth2 and session-cookie auth. Drives the
|
|
16
|
+
* browser and (for cookie) the "press Enter to capture" handoff through Ink's
|
|
17
|
+
* own input, so it works inside the TUI as well as the standalone command —
|
|
18
|
+
* neither needs to own raw stdin the way the old console prompt did.
|
|
19
|
+
*/
|
|
20
|
+
export declare function AuthLoginScreen({ method, devProperties, onComplete, onError, onCancel, }: Props): React.JSX.Element;
|
|
21
|
+
export {};
|