@super-protocol/sp-cli 0.0.7 → 0.0.8
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/README.md +57 -43
- package/dist/commands/account/base.d.ts +1 -2
- package/dist/commands/account/base.js +4 -11
- package/dist/commands/account/forget.d.ts +2 -1
- package/dist/commands/account/forget.js +21 -4
- package/dist/commands/account/login.js +3 -8
- package/dist/commands/base.js +96 -12
- package/dist/commands/storage/base.js +11 -11
- package/dist/commands/storage/select.js +3 -3
- package/dist/commands/storage/update.js +10 -10
- package/dist/commands/workflows/extend-lease.d.ts +1 -1
- package/dist/commands/workflows/extend-lease.js +2 -3
- package/dist/utils/prompt-flags.d.ts +20 -0
- package/dist/utils/prompt-flags.js +121 -0
- package/dist/utils/prompt.service.d.ts +16 -0
- package/dist/utils/prompt.service.js +75 -0
- package/dist/utils/tty.d.ts +1 -0
- package/dist/utils/tty.js +3 -0
- package/oclif.manifest.json +265 -160
- package/package.json +1 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { password, select, text } from '@clack/prompts';
|
|
2
1
|
import { StorageType } from '@super-protocol/provider-client';
|
|
3
2
|
import { BaseCommand } from '../../commands/base.js';
|
|
4
3
|
import { S3_REGION } from '../../constants.js';
|
|
5
4
|
import { StorageService } from '../../services/storage.service.js';
|
|
5
|
+
import { promptService } from '../../utils/prompt.service.js';
|
|
6
6
|
export class BaseStorageCommand extends BaseCommand {
|
|
7
7
|
currentDir = process.cwd();
|
|
8
8
|
storageService;
|
|
@@ -14,25 +14,25 @@ export class BaseStorageCommand extends BaseCommand {
|
|
|
14
14
|
}
|
|
15
15
|
async promptS3Credentials() {
|
|
16
16
|
const region = S3_REGION;
|
|
17
|
-
const readAccessKeyId =
|
|
17
|
+
const readAccessKeyId = (await promptService.text({
|
|
18
18
|
message: 'Read access key ID',
|
|
19
19
|
validate(value) {
|
|
20
20
|
return value ? undefined : 'Read access key ID is required';
|
|
21
21
|
},
|
|
22
22
|
})).trim();
|
|
23
|
-
const readSecretAccessKey =
|
|
23
|
+
const readSecretAccessKey = (await promptService.password({
|
|
24
24
|
message: 'Read secret access key',
|
|
25
25
|
validate(value) {
|
|
26
26
|
return value ? undefined : 'Read secret access key is required';
|
|
27
27
|
},
|
|
28
28
|
})).trim();
|
|
29
|
-
const writeAccessKeyId =
|
|
29
|
+
const writeAccessKeyId = (await promptService.text({
|
|
30
30
|
message: 'Write access key ID',
|
|
31
31
|
validate(value) {
|
|
32
32
|
return value ? undefined : 'Write access key ID is required';
|
|
33
33
|
},
|
|
34
34
|
})).trim();
|
|
35
|
-
const writeSecretAccessKey =
|
|
35
|
+
const writeSecretAccessKey = (await promptService.password({
|
|
36
36
|
message: 'Write secret access key',
|
|
37
37
|
validate(value) {
|
|
38
38
|
return value ? undefined : 'Write secret access key is required';
|
|
@@ -47,20 +47,20 @@ export class BaseStorageCommand extends BaseCommand {
|
|
|
47
47
|
};
|
|
48
48
|
}
|
|
49
49
|
async promptStoragePayload() {
|
|
50
|
-
const storageType =
|
|
50
|
+
const storageType = await promptService.select({
|
|
51
51
|
message: 'Select storage type',
|
|
52
52
|
options: [
|
|
53
53
|
{ label: 'S3', value: StorageType.S3 },
|
|
54
54
|
{ label: 'StorJ', value: StorageType.StorJ },
|
|
55
55
|
],
|
|
56
|
-
})
|
|
57
|
-
const bucket =
|
|
56
|
+
});
|
|
57
|
+
const bucket = (await promptService.text({
|
|
58
58
|
message: 'Bucket name',
|
|
59
59
|
validate(value) {
|
|
60
60
|
return value ? undefined : 'Bucket is required';
|
|
61
61
|
},
|
|
62
62
|
})).trim();
|
|
63
|
-
const prefix =
|
|
63
|
+
const prefix = (await promptService.text({
|
|
64
64
|
defaultValue: '/',
|
|
65
65
|
initialValue: '/',
|
|
66
66
|
message: 'Prefix',
|
|
@@ -82,13 +82,13 @@ export class BaseStorageCommand extends BaseCommand {
|
|
|
82
82
|
return storage;
|
|
83
83
|
}
|
|
84
84
|
async promptStorJCredentials() {
|
|
85
|
-
const readAccessToken =
|
|
85
|
+
const readAccessToken = (await promptService.password({
|
|
86
86
|
message: 'Read access token',
|
|
87
87
|
validate(value) {
|
|
88
88
|
return value ? undefined : 'Read access token is required';
|
|
89
89
|
},
|
|
90
90
|
})).trim();
|
|
91
|
-
const writeAccessToken =
|
|
91
|
+
const writeAccessToken = (await promptService.password({
|
|
92
92
|
message: 'Write access token',
|
|
93
93
|
validate(value) {
|
|
94
94
|
return value ? undefined : 'Write access token is required';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { select } from '@clack/prompts';
|
|
2
1
|
import { StoragesUndefinedError } from '../../services/storage.service.js';
|
|
2
|
+
import { promptService } from '../../utils/prompt.service.js';
|
|
3
3
|
import { BaseStorageCommand } from './base.js';
|
|
4
4
|
export default class StorageSelect extends BaseStorageCommand {
|
|
5
5
|
static description = 'Select a storage that will be used by subsequent commands.';
|
|
@@ -7,13 +7,13 @@ export default class StorageSelect extends BaseStorageCommand {
|
|
|
7
7
|
async run() {
|
|
8
8
|
try {
|
|
9
9
|
const storages = await this.storageService.requestStorages();
|
|
10
|
-
const storageId =
|
|
10
|
+
const storageId = await promptService.select({
|
|
11
11
|
message: 'Select storage',
|
|
12
12
|
options: storages.map((storage) => ({
|
|
13
13
|
label: this.storageService.getLabel(storage),
|
|
14
14
|
value: storage.id,
|
|
15
15
|
})),
|
|
16
|
-
})
|
|
16
|
+
});
|
|
17
17
|
if (!storageId) {
|
|
18
18
|
this.error('Storage ID is required');
|
|
19
19
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { confirm, select, text } from '@clack/prompts';
|
|
4
3
|
import { Flags } from '@oclif/core';
|
|
5
4
|
import { StorageType, } from '@super-protocol/provider-client';
|
|
6
5
|
import { StoragesUndefinedError } from '../../services/storage.service.js';
|
|
6
|
+
import { promptService } from '../../utils/prompt.service.js';
|
|
7
7
|
import { BaseStorageCommand } from './base.js';
|
|
8
8
|
export default class StorageUpdate extends BaseStorageCommand {
|
|
9
9
|
static description = 'Update the configuration of an existing storage.';
|
|
@@ -39,10 +39,10 @@ export default class StorageUpdate extends BaseStorageCommand {
|
|
|
39
39
|
if (!options || options.length === 0) {
|
|
40
40
|
throw new StoragesUndefinedError('No storages available to update');
|
|
41
41
|
}
|
|
42
|
-
storageId =
|
|
42
|
+
storageId = await promptService.select({
|
|
43
43
|
message: 'Select storage to update',
|
|
44
44
|
options,
|
|
45
|
-
})
|
|
45
|
+
});
|
|
46
46
|
}
|
|
47
47
|
if (!storageId) {
|
|
48
48
|
this.error('Storage ID is required');
|
|
@@ -148,14 +148,14 @@ export default class StorageUpdate extends BaseStorageCommand {
|
|
|
148
148
|
}
|
|
149
149
|
async promptStorageUpdate(existingStorage) {
|
|
150
150
|
const payload = {};
|
|
151
|
-
const bucket =
|
|
151
|
+
const bucket = (await promptService.text({
|
|
152
152
|
defaultValue: existingStorage?.bucket ?? '',
|
|
153
153
|
message: 'Bucket name (leave empty to keep current)',
|
|
154
154
|
})).trim();
|
|
155
155
|
if (bucket) {
|
|
156
156
|
payload.bucket = bucket;
|
|
157
157
|
}
|
|
158
|
-
const prefix =
|
|
158
|
+
const prefix = (await promptService.text({
|
|
159
159
|
defaultValue: existingStorage?.prefix ?? '',
|
|
160
160
|
message: 'Prefix (leave empty to keep current)',
|
|
161
161
|
})).trim();
|
|
@@ -163,27 +163,27 @@ export default class StorageUpdate extends BaseStorageCommand {
|
|
|
163
163
|
payload.prefix = prefix;
|
|
164
164
|
}
|
|
165
165
|
let newStorageType;
|
|
166
|
-
const shouldChangeType =
|
|
166
|
+
const shouldChangeType = await promptService.confirm({
|
|
167
167
|
initialValue: false,
|
|
168
168
|
message: existingStorage
|
|
169
169
|
? `Change storage type? (current: ${existingStorage.storageType})`
|
|
170
170
|
: 'Change storage type?',
|
|
171
|
-
})
|
|
171
|
+
});
|
|
172
172
|
if (shouldChangeType) {
|
|
173
|
-
newStorageType =
|
|
173
|
+
newStorageType = await promptService.select({
|
|
174
174
|
message: 'Select new storage type',
|
|
175
175
|
options: [
|
|
176
176
|
{ label: 'Amazon S3', value: StorageType.S3 },
|
|
177
177
|
{ label: 'StorJ', value: StorageType.StorJ },
|
|
178
178
|
],
|
|
179
|
-
})
|
|
179
|
+
});
|
|
180
180
|
payload.storageType = newStorageType;
|
|
181
181
|
}
|
|
182
182
|
const effectiveType = newStorageType ?? existingStorage?.storageType;
|
|
183
183
|
const credentialsRequired = Boolean(newStorageType);
|
|
184
184
|
if (effectiveType) {
|
|
185
185
|
const updateCredentials = credentialsRequired ||
|
|
186
|
-
|
|
186
|
+
(await promptService.confirm({
|
|
187
187
|
initialValue: false,
|
|
188
188
|
message: `Update ${effectiveType} credentials?`,
|
|
189
189
|
}));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type SelectOptions } from '
|
|
1
|
+
import { type SelectOptions } from '../../utils/prompt.service.js';
|
|
2
2
|
import { BaseCommand } from '../base.js';
|
|
3
3
|
export default class WorkflowsExtendLease extends BaseCommand<typeof WorkflowsExtendLease> {
|
|
4
4
|
static args: {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { select } from '@clack/prompts';
|
|
2
1
|
import { Args, Flags } from '@oclif/core';
|
|
3
2
|
import { Orders } from '@super-protocol/sdk-js';
|
|
4
3
|
import { formatEther, parseEther } from 'viem/utils';
|
|
4
|
+
import { promptService } from '../../utils/prompt.service.js';
|
|
5
5
|
import { BaseCommand } from '../base.js';
|
|
6
6
|
export default class WorkflowsExtendLease extends BaseCommand {
|
|
7
7
|
static args = {
|
|
@@ -97,7 +97,6 @@ export default class WorkflowsExtendLease extends BaseCommand {
|
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
async selectPrompt(options) {
|
|
100
|
-
|
|
101
|
-
return this.ensurePromptValue(result);
|
|
100
|
+
return promptService.select(options);
|
|
102
101
|
}
|
|
103
102
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Args, Flags } from '@oclif/core';
|
|
2
|
+
type FlagDefinition = ReturnType<typeof Flags.string> | ReturnType<typeof Flags.integer> | ReturnType<typeof Flags.boolean>;
|
|
3
|
+
type ArgDefinition = ReturnType<typeof Args.string> | ReturnType<typeof Args.integer> | ReturnType<typeof Args.boolean>;
|
|
4
|
+
export interface MissingFlag {
|
|
5
|
+
name: string;
|
|
6
|
+
definition: FlagDefinition;
|
|
7
|
+
type: 'string' | 'integer' | 'boolean';
|
|
8
|
+
}
|
|
9
|
+
export interface MissingArg {
|
|
10
|
+
name: string;
|
|
11
|
+
definition: ArgDefinition;
|
|
12
|
+
type: 'string' | 'integer' | 'boolean';
|
|
13
|
+
}
|
|
14
|
+
export declare const findMissingRequiredFlags: (flags: Record<string, unknown>, flagDefinitions: Record<string, FlagDefinition> | undefined) => Promise<MissingFlag[]>;
|
|
15
|
+
export declare const findMissingRequiredArgs: (args: Record<string, unknown>, argDefinitions: Record<string, ArgDefinition> | undefined) => Promise<MissingArg[]>;
|
|
16
|
+
export declare const promptForFlag: (missingFlag: MissingFlag) => Promise<string | number | boolean>;
|
|
17
|
+
export declare const promptForArg: (missingArg: MissingArg) => Promise<string | number | boolean>;
|
|
18
|
+
export declare const formatMissingFlagsError: (missingFlags: MissingFlag[]) => string;
|
|
19
|
+
export declare const formatMissingArgsError: (missingArgs: MissingArg[]) => string;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { promptService } from './prompt.service.js';
|
|
2
|
+
const getSampleValue = (definition) => {
|
|
3
|
+
if (typeof definition.min === 'number') {
|
|
4
|
+
return String(definition.min);
|
|
5
|
+
}
|
|
6
|
+
if (typeof definition.max === 'number' && definition.max < 1) {
|
|
7
|
+
return String(definition.max);
|
|
8
|
+
}
|
|
9
|
+
return '1';
|
|
10
|
+
};
|
|
11
|
+
const inferTypeFromDefinition = async (definition, allowNo) => {
|
|
12
|
+
if (definition && typeof definition === 'object') {
|
|
13
|
+
const typedDefinition = definition;
|
|
14
|
+
if (typedDefinition.type === 'boolean' || typedDefinition.type === 'flag') {
|
|
15
|
+
return 'boolean';
|
|
16
|
+
}
|
|
17
|
+
if (typedDefinition.type === 'integer' || typedDefinition.type === 'number') {
|
|
18
|
+
return 'integer';
|
|
19
|
+
}
|
|
20
|
+
if (allowNo && typeof typedDefinition.allowNo === 'boolean') {
|
|
21
|
+
return 'boolean';
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const parse = definition?.parse;
|
|
25
|
+
if (typeof parse === 'function') {
|
|
26
|
+
const sample = getSampleValue(definition);
|
|
27
|
+
try {
|
|
28
|
+
const parsed = await parse(sample, {}, definition);
|
|
29
|
+
if (typeof parsed === 'number') {
|
|
30
|
+
return 'integer';
|
|
31
|
+
}
|
|
32
|
+
if (typeof parsed === 'boolean') {
|
|
33
|
+
return 'boolean';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// Ignore parsing errors for type inference.
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return 'string';
|
|
41
|
+
};
|
|
42
|
+
const parseIntegerValue = (name, input, definition) => {
|
|
43
|
+
if (!/^-?\d+$/.test(input)) {
|
|
44
|
+
throw new Error(`${name} must be a number`);
|
|
45
|
+
}
|
|
46
|
+
const num = Number.parseInt(input, 10);
|
|
47
|
+
if (definition.min !== undefined && num < definition.min) {
|
|
48
|
+
throw new Error(`Expected an integer greater than or equal to ${definition.min} but received: ${input}`);
|
|
49
|
+
}
|
|
50
|
+
if (definition.max !== undefined && num > definition.max) {
|
|
51
|
+
throw new Error(`Expected an integer less than or equal to ${definition.max} but received: ${input}`);
|
|
52
|
+
}
|
|
53
|
+
return num;
|
|
54
|
+
};
|
|
55
|
+
const getFlagType = async (definition) => inferTypeFromDefinition(definition, true);
|
|
56
|
+
export const findMissingRequiredFlags = async (flags, flagDefinitions) => {
|
|
57
|
+
if (!flagDefinitions) {
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
const missing = [];
|
|
61
|
+
for (const [name, definition] of Object.entries(flagDefinitions)) {
|
|
62
|
+
if (definition.required && (flags[name] === undefined || flags[name] === null)) {
|
|
63
|
+
missing.push({
|
|
64
|
+
name,
|
|
65
|
+
definition,
|
|
66
|
+
type: await getFlagType(definition),
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return missing;
|
|
71
|
+
};
|
|
72
|
+
const getArgType = async (definition) => inferTypeFromDefinition(definition, false);
|
|
73
|
+
export const findMissingRequiredArgs = async (args, argDefinitions) => {
|
|
74
|
+
if (!argDefinitions) {
|
|
75
|
+
return [];
|
|
76
|
+
}
|
|
77
|
+
const missing = [];
|
|
78
|
+
for (const [name, definition] of Object.entries(argDefinitions)) {
|
|
79
|
+
if (definition.required && (args[name] === undefined || args[name] === null)) {
|
|
80
|
+
missing.push({
|
|
81
|
+
name,
|
|
82
|
+
definition,
|
|
83
|
+
type: await getArgType(definition),
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return missing;
|
|
88
|
+
};
|
|
89
|
+
export const promptForFlag = async (missingFlag) => {
|
|
90
|
+
const description = missingFlag.definition.description;
|
|
91
|
+
const optionValues = missingFlag.definition.options;
|
|
92
|
+
if (missingFlag.type === 'string' && Array.isArray(optionValues) && optionValues.length > 0) {
|
|
93
|
+
const message = description ? `Select ${description}` : `Select ${missingFlag.name}`;
|
|
94
|
+
return promptService.select({
|
|
95
|
+
message,
|
|
96
|
+
options: optionValues.map((value) => ({
|
|
97
|
+
label: value,
|
|
98
|
+
value,
|
|
99
|
+
})),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
const parseValue = missingFlag.type === 'integer'
|
|
103
|
+
? (input) => parseIntegerValue(missingFlag.name, input, missingFlag.definition)
|
|
104
|
+
: undefined;
|
|
105
|
+
return promptService.promptForValue(missingFlag.name, description, missingFlag.type, parseValue);
|
|
106
|
+
};
|
|
107
|
+
export const promptForArg = async (missingArg) => {
|
|
108
|
+
const description = missingArg.definition.description;
|
|
109
|
+
const parseValue = missingArg.type === 'integer'
|
|
110
|
+
? (input) => parseIntegerValue(missingArg.name, input, missingArg.definition)
|
|
111
|
+
: undefined;
|
|
112
|
+
return promptService.promptForValue(missingArg.name, description, missingArg.type, parseValue);
|
|
113
|
+
};
|
|
114
|
+
export const formatMissingFlagsError = (missingFlags) => {
|
|
115
|
+
const flagNames = missingFlags.map((f) => `--${f.name}`).join(', ');
|
|
116
|
+
return `Missing required flags: ${flagNames}. Please provide them or run in interactive mode.`;
|
|
117
|
+
};
|
|
118
|
+
export const formatMissingArgsError = (missingArgs) => {
|
|
119
|
+
const argNames = missingArgs.map((a) => `<${a.name}>`).join(', ');
|
|
120
|
+
return `Missing required arguments: ${argNames}. Please provide them or run in interactive mode.`;
|
|
121
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type ConfirmOptions as ClackConfirmOptions, type PasswordOptions as ClackPasswordOptions, type SelectOptions as ClackSelectOptions, type TextOptions as ClackTextOptions } from '@clack/prompts';
|
|
2
|
+
export type TextOptions = ClackTextOptions;
|
|
3
|
+
export type ConfirmOptions = ClackConfirmOptions;
|
|
4
|
+
export type SelectOptions<T> = ClackSelectOptions<T>;
|
|
5
|
+
export type PasswordOptions = ClackPasswordOptions;
|
|
6
|
+
type ParseValue = (input: string) => string | number | boolean;
|
|
7
|
+
export declare class PromptService {
|
|
8
|
+
text(options: ClackTextOptions): Promise<string>;
|
|
9
|
+
confirm(options: ClackConfirmOptions): Promise<boolean>;
|
|
10
|
+
select<T>(options: ClackSelectOptions<T>): Promise<T>;
|
|
11
|
+
password(options: ClackPasswordOptions): Promise<string>;
|
|
12
|
+
ensureValue<T>(value: symbol | T, errorMessage?: string): T;
|
|
13
|
+
promptForValue(name: string, description: string | undefined, type: 'string' | 'integer' | 'boolean', parseValue?: ParseValue): Promise<string | number | boolean>;
|
|
14
|
+
}
|
|
15
|
+
export declare const promptService: PromptService;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { confirm as clackConfirm, password as clackPassword, select as clackSelect, text as clackText, isCancel, } from '@clack/prompts';
|
|
2
|
+
export class PromptService {
|
|
3
|
+
async text(options) {
|
|
4
|
+
const result = await clackText(options);
|
|
5
|
+
if (isCancel(result)) {
|
|
6
|
+
throw new Error('Operation cancelled.');
|
|
7
|
+
}
|
|
8
|
+
return result;
|
|
9
|
+
}
|
|
10
|
+
async confirm(options) {
|
|
11
|
+
const result = await clackConfirm(options);
|
|
12
|
+
if (isCancel(result)) {
|
|
13
|
+
throw new Error('Operation cancelled.');
|
|
14
|
+
}
|
|
15
|
+
return result;
|
|
16
|
+
}
|
|
17
|
+
async select(options) {
|
|
18
|
+
const result = await clackSelect(options);
|
|
19
|
+
if (isCancel(result)) {
|
|
20
|
+
throw new Error('Operation cancelled.');
|
|
21
|
+
}
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
24
|
+
async password(options) {
|
|
25
|
+
const result = await clackPassword(options);
|
|
26
|
+
if (isCancel(result)) {
|
|
27
|
+
throw new Error('Operation cancelled.');
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
ensureValue(value, errorMessage = 'Operation cancelled.') {
|
|
32
|
+
if (isCancel(value)) {
|
|
33
|
+
throw new Error(errorMessage);
|
|
34
|
+
}
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
async promptForValue(name, description, type, parseValue) {
|
|
38
|
+
const fullDescription = description ? ` (${description})` : '';
|
|
39
|
+
if (type === 'boolean') {
|
|
40
|
+
const message = `Enable ${name}${fullDescription}?`;
|
|
41
|
+
return await this.confirm({ message });
|
|
42
|
+
}
|
|
43
|
+
const message = `Please provide ${name}${fullDescription}:`;
|
|
44
|
+
const parseInput = (value) => {
|
|
45
|
+
if (parseValue) {
|
|
46
|
+
return parseValue(value);
|
|
47
|
+
}
|
|
48
|
+
if (type === 'integer') {
|
|
49
|
+
const num = Number.parseInt(value, 10);
|
|
50
|
+
if (Number.isNaN(num)) {
|
|
51
|
+
throw new Error(`${name} must be a number`);
|
|
52
|
+
}
|
|
53
|
+
return num;
|
|
54
|
+
}
|
|
55
|
+
return value;
|
|
56
|
+
};
|
|
57
|
+
const result = await this.text({
|
|
58
|
+
message,
|
|
59
|
+
validate: (value) => {
|
|
60
|
+
if (!value || value.trim() === '') {
|
|
61
|
+
return `${name} is required`;
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
parseInput(value);
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
return error instanceof Error ? error.message : String(error);
|
|
68
|
+
}
|
|
69
|
+
return;
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
return parseInput(result);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export const promptService = new PromptService();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const isInteractiveMode: (ttyFlag?: boolean) => boolean;
|