@fold-run/cli 0.1.1 → 0.1.3
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/commands/delete.d.ts +1 -0
- package/dist/commands/delete.js +8 -0
- package/dist/commands/delete.js.map +1 -1
- package/dist/commands/deploy.js +26 -17
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/dev.js +13 -17
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/env-vars.d.ts +1 -0
- package/dist/commands/env-vars.js +8 -1
- package/dist/commands/env-vars.js.map +1 -1
- package/dist/commands/init.js +31 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/login.js +8 -6
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/schedules.d.ts +3 -1
- package/dist/commands/schedules.js +41 -21
- package/dist/commands/schedules.js.map +1 -1
- package/dist/commands/secrets.d.ts +3 -1
- package/dist/commands/secrets.js +9 -2
- package/dist/commands/secrets.js.map +1 -1
- package/dist/commands/status.js +48 -28
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/templates.js +24 -17
- package/dist/commands/templates.js.map +1 -1
- package/dist/commands/tenant.d.ts +4 -0
- package/dist/commands/tenant.js +82 -0
- package/dist/commands/tenant.js.map +1 -0
- package/dist/commands/webhooks.d.ts +3 -1
- package/dist/commands/webhooks.js +31 -18
- package/dist/commands/webhooks.js.map +1 -1
- package/dist/index.js +36 -15
- package/dist/index.js.map +1 -1
- package/dist/lib/cron.d.ts +13 -0
- package/dist/lib/cron.js +107 -0
- package/dist/lib/cron.js.map +1 -0
- package/dist/lib/manifest.d.ts +31 -0
- package/dist/lib/manifest.js +195 -0
- package/dist/lib/manifest.js.map +1 -0
- package/dist/lib/prompt.d.ts +5 -0
- package/dist/lib/prompt.js +14 -0
- package/dist/lib/prompt.js.map +1 -1
- package/dist/lib/spinner.d.ts +14 -0
- package/dist/lib/spinner.js +52 -0
- package/dist/lib/spinner.js.map +1 -0
- package/dist/lib/version-check.d.ts +9 -0
- package/dist/lib/version-check.js +54 -0
- package/dist/lib/version-check.js.map +1 -0
- package/package.json +1 -1
package/dist/lib/cron.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// Cron expression validator for standard 5-field cron format:
|
|
2
|
+
// minute hour day-of-month month day-of-week
|
|
3
|
+
// Supports: numbers, ranges (1-5), steps (e.g. every 5), lists (1,3,5), wildcards (*)
|
|
4
|
+
const CRON_FIELDS = [
|
|
5
|
+
{ name: 'minute', min: 0, max: 59 },
|
|
6
|
+
{ name: 'hour', min: 0, max: 23 },
|
|
7
|
+
{ name: 'day of month', min: 1, max: 31 },
|
|
8
|
+
{ name: 'month', min: 1, max: 12 },
|
|
9
|
+
{ name: 'day of week', min: 0, max: 7 }, // 0 and 7 are both Sunday
|
|
10
|
+
];
|
|
11
|
+
// Validate a single cron field value (e.g., "5", "1-10", "1,5,10")
|
|
12
|
+
function validateField(value, field) {
|
|
13
|
+
// Wildcard
|
|
14
|
+
if (value === '*') {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
// Step values: */5 or 1-10/2
|
|
18
|
+
if (value.includes('/')) {
|
|
19
|
+
const [range, stepStr] = value.split('/');
|
|
20
|
+
const step = parseInt(stepStr, 10);
|
|
21
|
+
if (Number.isNaN(step) || step < 1) {
|
|
22
|
+
return `invalid step value "${stepStr}" in ${field.name}`;
|
|
23
|
+
}
|
|
24
|
+
// Validate the range part
|
|
25
|
+
if (range !== '*') {
|
|
26
|
+
const rangeError = validateField(range, field);
|
|
27
|
+
if (rangeError)
|
|
28
|
+
return rangeError;
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
// List values: 1,5,10
|
|
33
|
+
if (value.includes(',')) {
|
|
34
|
+
const parts = value.split(',');
|
|
35
|
+
for (const part of parts) {
|
|
36
|
+
const error = validateField(part.trim(), field);
|
|
37
|
+
if (error)
|
|
38
|
+
return error;
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
// Range values: 1-10
|
|
43
|
+
if (value.includes('-')) {
|
|
44
|
+
const [startStr, endStr] = value.split('-');
|
|
45
|
+
const start = parseInt(startStr, 10);
|
|
46
|
+
const end = parseInt(endStr, 10);
|
|
47
|
+
if (Number.isNaN(start) || Number.isNaN(end)) {
|
|
48
|
+
return `invalid range "${value}" in ${field.name}`;
|
|
49
|
+
}
|
|
50
|
+
if (start < field.min || start > field.max) {
|
|
51
|
+
return `${field.name} start value ${start} out of range (${field.min}-${field.max})`;
|
|
52
|
+
}
|
|
53
|
+
if (end < field.min || end > field.max) {
|
|
54
|
+
return `${field.name} end value ${end} out of range (${field.min}-${field.max})`;
|
|
55
|
+
}
|
|
56
|
+
if (start > end) {
|
|
57
|
+
return `invalid range "${value}" in ${field.name}: start > end`;
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
// Single number
|
|
62
|
+
const num = parseInt(value, 10);
|
|
63
|
+
if (Number.isNaN(num)) {
|
|
64
|
+
return `invalid value "${value}" in ${field.name}`;
|
|
65
|
+
}
|
|
66
|
+
if (num < field.min || num > field.max) {
|
|
67
|
+
return `${field.name} value ${num} out of range (${field.min}-${field.max})`;
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Validate a cron expression.
|
|
73
|
+
* Returns { valid: true } or { valid: false, error: "..." }
|
|
74
|
+
*/
|
|
75
|
+
export function validateCron(expression) {
|
|
76
|
+
const trimmed = expression.trim();
|
|
77
|
+
if (!trimmed) {
|
|
78
|
+
return { valid: false, error: 'cron expression cannot be empty' };
|
|
79
|
+
}
|
|
80
|
+
const fields = trimmed.split(/\s+/);
|
|
81
|
+
if (fields.length !== 5) {
|
|
82
|
+
return {
|
|
83
|
+
valid: false,
|
|
84
|
+
error: `expected 5 fields (minute hour day month weekday), got ${fields.length}`,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
for (let i = 0; i < 5; i++) {
|
|
88
|
+
const error = validateField(fields[i], CRON_FIELDS[i]);
|
|
89
|
+
if (error) {
|
|
90
|
+
return { valid: false, error };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return { valid: true };
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Format a cron validation error with usage hint.
|
|
97
|
+
*/
|
|
98
|
+
export function formatCronError(error) {
|
|
99
|
+
return `Invalid cron expression: ${error}
|
|
100
|
+
|
|
101
|
+
Format: <minute> <hour> <day> <month> <weekday>
|
|
102
|
+
Examples:
|
|
103
|
+
*/5 * * * * Every 5 minutes
|
|
104
|
+
0 9 * * 1-5 9 AM on weekdays
|
|
105
|
+
0 0 1 * * Midnight on the 1st of each month`;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=cron.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron.js","sourceRoot":"","sources":["../../src/lib/cron.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface FoldManifest {
|
|
2
|
+
name?: string;
|
|
3
|
+
entrypoint?: string;
|
|
4
|
+
tenant_id?: string;
|
|
5
|
+
intent?: {
|
|
6
|
+
trigger?: string;
|
|
7
|
+
bindings?: string[];
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export interface ManifestValidationError {
|
|
11
|
+
field: string;
|
|
12
|
+
message: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ManifestResult {
|
|
15
|
+
manifest: FoldManifest | null;
|
|
16
|
+
errors: ManifestValidationError[];
|
|
17
|
+
warnings: string[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Load and validate fold.json from current directory.
|
|
21
|
+
* Returns manifest (if valid), errors (blocking), and warnings (non-blocking).
|
|
22
|
+
*/
|
|
23
|
+
export declare function loadManifest(dir?: string): ManifestResult;
|
|
24
|
+
/**
|
|
25
|
+
* Format validation errors for display.
|
|
26
|
+
*/
|
|
27
|
+
export declare function formatManifestErrors(errors: ManifestValidationError[]): string;
|
|
28
|
+
/**
|
|
29
|
+
* Format warnings for display.
|
|
30
|
+
*/
|
|
31
|
+
export declare function formatManifestWarnings(warnings: string[]): string;
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
// fold.json manifest validation
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
const KNOWN_FIELDS = ['name', 'entrypoint', 'tenant_id', 'intent'];
|
|
5
|
+
const KNOWN_INTENT_FIELDS = ['trigger', 'bindings'];
|
|
6
|
+
const VALID_TRIGGERS = ['http', 'cron', 'webhook', 'queue'];
|
|
7
|
+
const VALID_BINDINGS = ['kv', 'storage', 'db', 'queue', 'ai'];
|
|
8
|
+
function validateType(value, field, expected) {
|
|
9
|
+
const actual = Array.isArray(value) ? 'array' : typeof value;
|
|
10
|
+
if (actual !== expected) {
|
|
11
|
+
return `"${field}" must be a ${expected}, got ${actual}`;
|
|
12
|
+
}
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Load and validate fold.json from current directory.
|
|
17
|
+
* Returns manifest (if valid), errors (blocking), and warnings (non-blocking).
|
|
18
|
+
*/
|
|
19
|
+
export function loadManifest(dir) {
|
|
20
|
+
const manifestPath = resolve(dir ?? '.', 'fold.json');
|
|
21
|
+
const errors = [];
|
|
22
|
+
const warnings = [];
|
|
23
|
+
if (!existsSync(manifestPath)) {
|
|
24
|
+
return { manifest: null, errors: [], warnings: [] };
|
|
25
|
+
}
|
|
26
|
+
let raw;
|
|
27
|
+
try {
|
|
28
|
+
raw = readFileSync(manifestPath, 'utf-8');
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
errors.push({ field: 'file', message: `Could not read fold.json: ${err}` });
|
|
32
|
+
return { manifest: null, errors, warnings };
|
|
33
|
+
}
|
|
34
|
+
let data;
|
|
35
|
+
try {
|
|
36
|
+
data = JSON.parse(raw);
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
const parseErr = err;
|
|
40
|
+
errors.push({ field: 'json', message: `Invalid JSON: ${parseErr.message}` });
|
|
41
|
+
return { manifest: null, errors, warnings };
|
|
42
|
+
}
|
|
43
|
+
if (typeof data !== 'object' || data === null || Array.isArray(data)) {
|
|
44
|
+
errors.push({ field: 'root', message: 'fold.json must be an object' });
|
|
45
|
+
return { manifest: null, errors, warnings };
|
|
46
|
+
}
|
|
47
|
+
const obj = data;
|
|
48
|
+
// Check for unknown top-level fields
|
|
49
|
+
for (const key of Object.keys(obj)) {
|
|
50
|
+
if (!KNOWN_FIELDS.includes(key)) {
|
|
51
|
+
warnings.push(`Unknown field "${key}" in fold.json (will be ignored)`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Validate name
|
|
55
|
+
if (obj.name !== undefined) {
|
|
56
|
+
const typeErr = validateType(obj.name, 'name', 'string');
|
|
57
|
+
if (typeErr) {
|
|
58
|
+
errors.push({ field: 'name', message: typeErr });
|
|
59
|
+
}
|
|
60
|
+
else if (typeof obj.name === 'string') {
|
|
61
|
+
if (obj.name.trim() === '') {
|
|
62
|
+
errors.push({ field: 'name', message: '"name" cannot be empty' });
|
|
63
|
+
}
|
|
64
|
+
else if (!/^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/.test(obj.name)) {
|
|
65
|
+
errors.push({
|
|
66
|
+
field: 'name',
|
|
67
|
+
message: '"name" must be lowercase alphanumeric with hyphens (e.g., "my-function")',
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Validate entrypoint
|
|
73
|
+
if (obj.entrypoint !== undefined) {
|
|
74
|
+
const typeErr = validateType(obj.entrypoint, 'entrypoint', 'string');
|
|
75
|
+
if (typeErr) {
|
|
76
|
+
errors.push({ field: 'entrypoint', message: typeErr });
|
|
77
|
+
}
|
|
78
|
+
else if (typeof obj.entrypoint === 'string') {
|
|
79
|
+
if (obj.entrypoint.trim() === '') {
|
|
80
|
+
errors.push({ field: 'entrypoint', message: '"entrypoint" cannot be empty' });
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
const entryPath = resolve(dir ?? '.', obj.entrypoint);
|
|
84
|
+
if (!existsSync(entryPath)) {
|
|
85
|
+
errors.push({
|
|
86
|
+
field: 'entrypoint',
|
|
87
|
+
message: `Entrypoint file not found: ${obj.entrypoint}`,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Validate tenant_id
|
|
94
|
+
if (obj.tenant_id !== undefined) {
|
|
95
|
+
const typeErr = validateType(obj.tenant_id, 'tenant_id', 'string');
|
|
96
|
+
if (typeErr) {
|
|
97
|
+
errors.push({ field: 'tenant_id', message: typeErr });
|
|
98
|
+
}
|
|
99
|
+
else if (typeof obj.tenant_id === 'string' && obj.tenant_id.trim() === '') {
|
|
100
|
+
errors.push({ field: 'tenant_id', message: '"tenant_id" cannot be empty' });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// Validate intent
|
|
104
|
+
if (obj.intent !== undefined) {
|
|
105
|
+
const typeErr = validateType(obj.intent, 'intent', 'object');
|
|
106
|
+
if (typeErr) {
|
|
107
|
+
errors.push({ field: 'intent', message: typeErr });
|
|
108
|
+
}
|
|
109
|
+
else if (typeof obj.intent === 'object' && obj.intent !== null && !Array.isArray(obj.intent)) {
|
|
110
|
+
const intent = obj.intent;
|
|
111
|
+
// Check for unknown intent fields
|
|
112
|
+
for (const key of Object.keys(intent)) {
|
|
113
|
+
if (!KNOWN_INTENT_FIELDS.includes(key)) {
|
|
114
|
+
warnings.push(`Unknown field "intent.${key}" (will be ignored)`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Validate trigger
|
|
118
|
+
if (intent.trigger !== undefined) {
|
|
119
|
+
const triggerErr = validateType(intent.trigger, 'intent.trigger', 'string');
|
|
120
|
+
if (triggerErr) {
|
|
121
|
+
errors.push({ field: 'intent.trigger', message: triggerErr });
|
|
122
|
+
}
|
|
123
|
+
else if (typeof intent.trigger === 'string' && !VALID_TRIGGERS.includes(intent.trigger)) {
|
|
124
|
+
warnings.push(`Unknown trigger "${intent.trigger}" (valid: ${VALID_TRIGGERS.join(', ')})`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Validate bindings
|
|
128
|
+
if (intent.bindings !== undefined) {
|
|
129
|
+
const bindingsErr = validateType(intent.bindings, 'intent.bindings', 'array');
|
|
130
|
+
if (bindingsErr) {
|
|
131
|
+
errors.push({ field: 'intent.bindings', message: bindingsErr });
|
|
132
|
+
}
|
|
133
|
+
else if (Array.isArray(intent.bindings)) {
|
|
134
|
+
for (let i = 0; i < intent.bindings.length; i++) {
|
|
135
|
+
const b = intent.bindings[i];
|
|
136
|
+
if (typeof b !== 'string') {
|
|
137
|
+
errors.push({
|
|
138
|
+
field: `intent.bindings[${i}]`,
|
|
139
|
+
message: `Binding must be a string, got ${typeof b}`,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
else if (!VALID_BINDINGS.includes(b)) {
|
|
143
|
+
warnings.push(`Unknown binding "${b}" (valid: ${VALID_BINDINGS.join(', ')})`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (errors.length > 0) {
|
|
151
|
+
return { manifest: null, errors, warnings };
|
|
152
|
+
}
|
|
153
|
+
// Build validated manifest
|
|
154
|
+
const manifest = {};
|
|
155
|
+
if (typeof obj.name === 'string')
|
|
156
|
+
manifest.name = obj.name;
|
|
157
|
+
if (typeof obj.entrypoint === 'string')
|
|
158
|
+
manifest.entrypoint = obj.entrypoint;
|
|
159
|
+
if (typeof obj.tenant_id === 'string')
|
|
160
|
+
manifest.tenant_id = obj.tenant_id;
|
|
161
|
+
if (typeof obj.intent === 'object' && obj.intent !== null) {
|
|
162
|
+
const intent = obj.intent;
|
|
163
|
+
manifest.intent = {};
|
|
164
|
+
if (typeof intent.trigger === 'string')
|
|
165
|
+
manifest.intent.trigger = intent.trigger;
|
|
166
|
+
if (Array.isArray(intent.bindings)) {
|
|
167
|
+
manifest.intent.bindings = intent.bindings.filter((b) => typeof b === 'string');
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return { manifest, errors, warnings };
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Format validation errors for display.
|
|
174
|
+
*/
|
|
175
|
+
export function formatManifestErrors(errors) {
|
|
176
|
+
const lines = ['Invalid fold.json:', ''];
|
|
177
|
+
for (const err of errors) {
|
|
178
|
+
lines.push(` \x1b[31m✗\x1b[0m ${err.message}`);
|
|
179
|
+
}
|
|
180
|
+
lines.push('');
|
|
181
|
+
lines.push('Example fold.json:');
|
|
182
|
+
lines.push(' {');
|
|
183
|
+
lines.push(' "name": "my-function",');
|
|
184
|
+
lines.push(' "entrypoint": "function.ts",');
|
|
185
|
+
lines.push(' "intent": { "bindings": ["kv"] }');
|
|
186
|
+
lines.push(' }');
|
|
187
|
+
return lines.join('\n');
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Format warnings for display.
|
|
191
|
+
*/
|
|
192
|
+
export function formatManifestWarnings(warnings) {
|
|
193
|
+
return warnings.map((w) => `\x1b[33mWarning:\x1b[0m ${w}`).join('\n');
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/lib/manifest.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/prompt.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt for yes/no confirmation. Returns true if user confirms.
|
|
3
|
+
* Defaults to 'no' if user just presses enter.
|
|
4
|
+
*/
|
|
5
|
+
export declare function confirm(message: string): Promise<boolean>;
|
|
1
6
|
/**
|
|
2
7
|
* Read a line of input with masked output (shows * for each character).
|
|
3
8
|
* Handles backspace and Ctrl+C.
|
package/dist/lib/prompt.js
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
import { stdin, stdout } from 'node:process';
|
|
2
|
+
import { createInterface } from 'node:readline';
|
|
3
|
+
/**
|
|
4
|
+
* Prompt for yes/no confirmation. Returns true if user confirms.
|
|
5
|
+
* Defaults to 'no' if user just presses enter.
|
|
6
|
+
*/
|
|
7
|
+
export async function confirm(message) {
|
|
8
|
+
const rl = createInterface({ input: stdin, output: stdout });
|
|
9
|
+
return new Promise((resolve) => {
|
|
10
|
+
rl.question(`${message} [y/N] `, (answer) => {
|
|
11
|
+
rl.close();
|
|
12
|
+
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
}
|
|
2
16
|
/**
|
|
3
17
|
* Read a line of input with masked output (shows * for each character).
|
|
4
18
|
* Handles backspace and Ctrl+C.
|
package/dist/lib/prompt.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/lib/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/lib/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,OAAe;IAC3C,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,EAAE,CAAC,QAAQ,CAAC,GAAG,OAAO,SAAS,EAAE,CAAC,MAAM,EAAE,EAAE;YAC1C,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,GAAG,IAAI,MAAM,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC,CAAC;QAC1E,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,MAAc;IACvC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACrB,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACvB,KAAK,CAAC,MAAM,EAAE,CAAC;QACf,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAE3B,MAAM,MAAM,GAAG,CAAC,EAAU,EAAE,EAAE;YAC5B,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;gBAC/B,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;gBACxB,KAAK,CAAC,KAAK,EAAE,CAAC;gBACd,KAAK,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBACrC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACnB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YAC1B,CAAC;iBAAM,IAAI,EAAE,KAAK,QAAQ,EAAE,CAAC;gBAC3B,SAAS;gBACT,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;gBACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;iBAAM,IAAI,EAAE,KAAK,QAAQ,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;gBAC1C,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACrB,KAAK,CAAC,GAAG,EAAE,CAAC;oBACZ,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBACxB,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACf,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACpB,CAAC;QACH,CAAC,CAAC;QACF,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface Spinner {
|
|
2
|
+
/** Update the spinner message */
|
|
3
|
+
update(message: string): void;
|
|
4
|
+
/** Stop spinner with success checkmark */
|
|
5
|
+
success(message?: string): void;
|
|
6
|
+
/** Stop spinner with failure X */
|
|
7
|
+
fail(message?: string): void;
|
|
8
|
+
/** Stop spinner without status icon */
|
|
9
|
+
stop(): void;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Create a terminal spinner. Returns no-op spinner if in JSON mode or non-TTY.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createSpinner(message: string): Spinner;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Simple terminal spinner without external dependencies
|
|
2
|
+
import { isJsonMode } from './output.js';
|
|
3
|
+
const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
4
|
+
const FRAME_INTERVAL_MS = 80;
|
|
5
|
+
/**
|
|
6
|
+
* Create a terminal spinner. Returns no-op spinner if in JSON mode or non-TTY.
|
|
7
|
+
*/
|
|
8
|
+
export function createSpinner(message) {
|
|
9
|
+
// Skip spinner in JSON mode or non-TTY environments
|
|
10
|
+
if (isJsonMode() || !process.stdout.isTTY) {
|
|
11
|
+
return {
|
|
12
|
+
update: () => { },
|
|
13
|
+
success: (msg) => msg && console.log(msg),
|
|
14
|
+
fail: (msg) => msg && console.error(msg),
|
|
15
|
+
stop: () => { },
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
let frameIndex = 0;
|
|
19
|
+
let currentMessage = message;
|
|
20
|
+
let stopped = false;
|
|
21
|
+
const render = () => {
|
|
22
|
+
if (stopped)
|
|
23
|
+
return;
|
|
24
|
+
const frame = SPINNER_FRAMES[frameIndex % SPINNER_FRAMES.length];
|
|
25
|
+
process.stdout.write(`\r\x1b[K${frame} ${currentMessage}`);
|
|
26
|
+
frameIndex++;
|
|
27
|
+
};
|
|
28
|
+
const interval = setInterval(render, FRAME_INTERVAL_MS);
|
|
29
|
+
render();
|
|
30
|
+
const clear = () => {
|
|
31
|
+
stopped = true;
|
|
32
|
+
clearInterval(interval);
|
|
33
|
+
process.stdout.write('\r\x1b[K');
|
|
34
|
+
};
|
|
35
|
+
return {
|
|
36
|
+
update(msg) {
|
|
37
|
+
currentMessage = msg;
|
|
38
|
+
},
|
|
39
|
+
success(msg) {
|
|
40
|
+
clear();
|
|
41
|
+
console.log(`\x1b[32m✓\x1b[0m ${msg ?? currentMessage}`);
|
|
42
|
+
},
|
|
43
|
+
fail(msg) {
|
|
44
|
+
clear();
|
|
45
|
+
console.log(`\x1b[31m✗\x1b[0m ${msg ?? currentMessage}`);
|
|
46
|
+
},
|
|
47
|
+
stop() {
|
|
48
|
+
clear();
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=spinner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spinner.js","sourceRoot":"","sources":["../../src/lib/spinner.ts"],"names":[],"mappings":"AAAA,wDAAwD;AAExD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAC1E,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAa7B;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,OAAe;IAC3C,oDAAoD;IACpD,IAAI,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAC1C,OAAO;YACL,MAAM,EAAE,GAAG,EAAE,GAAE,CAAC;YAChB,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;YACzC,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,IAAI,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC;YACxC,IAAI,EAAE,GAAG,EAAE,GAAE,CAAC;SACf,CAAC;IACJ,CAAC;IAED,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,cAAc,GAAG,OAAO,CAAC;IAC7B,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,MAAM,MAAM,GAAG,GAAG,EAAE;QAClB,IAAI,OAAO;YAAE,OAAO;QACpB,MAAM,KAAK,GAAG,cAAc,CAAC,UAAU,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;QACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,KAAK,IAAI,cAAc,EAAE,CAAC,CAAC;QAC3D,UAAU,EAAE,CAAC;IACf,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IACxD,MAAM,EAAE,CAAC;IAET,MAAM,KAAK,GAAG,GAAG,EAAE;QACjB,OAAO,GAAG,IAAI,CAAC;QACf,aAAa,CAAC,QAAQ,CAAC,CAAC;QACxB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACnC,CAAC,CAAC;IAEF,OAAO;QACL,MAAM,CAAC,GAAW;YAChB,cAAc,GAAG,GAAG,CAAC;QACvB,CAAC;QACD,OAAO,CAAC,GAAY;YAClB,KAAK,EAAE,CAAC;YACR,OAAO,CAAC,GAAG,CAAC,oBAAoB,GAAG,IAAI,cAAc,EAAE,CAAC,CAAC;QAC3D,CAAC;QACD,IAAI,CAAC,GAAY;YACf,KAAK,EAAE,CAAC;YACR,OAAO,CAAC,GAAG,CAAC,oBAAoB,GAAG,IAAI,cAAc,EAAE,CAAC,CAAC;QAC3D,CAAC;QACD,IAAI;YACF,KAAK,EAAE,CAAC;QACV,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check npm registry for newer version. Returns update message or null.
|
|
3
|
+
* Never throws - fails silently on network errors.
|
|
4
|
+
*/
|
|
5
|
+
export declare function checkForUpdate(): Promise<string | null>;
|
|
6
|
+
/**
|
|
7
|
+
* Print update notice if available. Non-blocking.
|
|
8
|
+
*/
|
|
9
|
+
export declare function printUpdateNotice(notice: string | null): void;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Version check utility - checks npm for newer CLI version
|
|
2
|
+
// Runs asynchronously and never blocks or throws
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
|
+
const require = createRequire(import.meta.url);
|
|
5
|
+
const { version: currentVersion } = require('../../package.json');
|
|
6
|
+
const NPM_REGISTRY = 'https://registry.npmjs.org/@fold-run/cli/latest';
|
|
7
|
+
const CHECK_TIMEOUT_MS = 2000;
|
|
8
|
+
function compareVersions(current, latest) {
|
|
9
|
+
const c = current.split('.').map(Number);
|
|
10
|
+
const l = latest.split('.').map(Number);
|
|
11
|
+
for (let i = 0; i < 3; i++) {
|
|
12
|
+
if ((l[i] ?? 0) > (c[i] ?? 0))
|
|
13
|
+
return 1;
|
|
14
|
+
if ((l[i] ?? 0) < (c[i] ?? 0))
|
|
15
|
+
return -1;
|
|
16
|
+
}
|
|
17
|
+
return 0;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Check npm registry for newer version. Returns update message or null.
|
|
21
|
+
* Never throws - fails silently on network errors.
|
|
22
|
+
*/
|
|
23
|
+
export async function checkForUpdate() {
|
|
24
|
+
try {
|
|
25
|
+
const controller = new AbortController();
|
|
26
|
+
const timeout = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS);
|
|
27
|
+
const res = await fetch(NPM_REGISTRY, {
|
|
28
|
+
signal: controller.signal,
|
|
29
|
+
headers: { Accept: 'application/json' },
|
|
30
|
+
});
|
|
31
|
+
clearTimeout(timeout);
|
|
32
|
+
if (!res.ok)
|
|
33
|
+
return null;
|
|
34
|
+
const data = (await res.json());
|
|
35
|
+
const latestVersion = data.version;
|
|
36
|
+
if (compareVersions(currentVersion, latestVersion) > 0) {
|
|
37
|
+
return `\x1b[33mUpdate available:\x1b[0m ${currentVersion} → \x1b[32m${latestVersion}\x1b[0m\n Run \x1b[36mnpm i -g @fold-run/cli\x1b[0m to update`;
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// Network error, timeout, etc - fail silently
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Print update notice if available. Non-blocking.
|
|
48
|
+
*/
|
|
49
|
+
export function printUpdateNotice(notice) {
|
|
50
|
+
if (notice) {
|
|
51
|
+
console.log(`\n${notice}\n`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=version-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version-check.js","sourceRoot":"","sources":["../../src/lib/version-check.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,iDAAiD;AAEjD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,oBAAoB,CAAwB,CAAC;AAEzF,MAAM,YAAY,GAAG,iDAAiD,CAAC;AACvE,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAM9B,SAAS,eAAe,CAAC,OAAe,EAAE,MAAc;IACtD,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACxC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC;QACxC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,gBAAgB,CAAC,CAAC;QAEvE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,YAAY,EAAE;YACpC,MAAM,EAAE,UAAU,CAAC,MAAM;YACzB,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;SACxC,CAAC,CAAC;QACH,YAAY,CAAC,OAAO,CAAC,CAAC;QAEtB,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QAEzB,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAe,CAAC;QAC9C,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC;QAEnC,IAAI,eAAe,CAAC,cAAc,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;YACvD,OAAO,oCAAoC,cAAc,cAAc,aAAa,gEAAgE,CAAC;QACvJ,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,8CAA8C;QAC9C,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAqB;IACrD,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,IAAI,CAAC,CAAC;IAC/B,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED