@scalebun/cli 1.10.2 → 1.11.0
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/lib/commands/ci-init.d.ts.map +1 -1
- package/lib/commands/ci-init.js +80 -2
- package/lib/commands/ci-init.js.map +1 -1
- package/lib/commands/doctor.d.ts.map +1 -1
- package/lib/commands/doctor.js +148 -3
- package/lib/commands/doctor.js.map +1 -1
- package/lib/commands/link.d.ts +16 -0
- package/lib/commands/link.d.ts.map +1 -0
- package/lib/commands/link.js +164 -0
- package/lib/commands/link.js.map +1 -0
- package/lib/commands/login.d.ts.map +1 -1
- package/lib/commands/login.js +29 -7
- package/lib/commands/login.js.map +1 -1
- package/lib/commands/ota-bundle.d.ts +15 -2
- package/lib/commands/ota-bundle.d.ts.map +1 -1
- package/lib/commands/ota-bundle.js +142 -12
- package/lib/commands/ota-bundle.js.map +1 -1
- package/lib/commands/ota-channels.d.ts.map +1 -1
- package/lib/commands/ota-channels.js +213 -21
- package/lib/commands/ota-channels.js.map +1 -1
- package/lib/commands/ota-inspect.d.ts +3 -0
- package/lib/commands/ota-inspect.d.ts.map +1 -0
- package/lib/commands/ota-inspect.js +258 -0
- package/lib/commands/ota-inspect.js.map +1 -0
- package/lib/commands/ota-keys.d.ts +18 -0
- package/lib/commands/ota-keys.d.ts.map +1 -1
- package/lib/commands/ota-keys.js +149 -4
- package/lib/commands/ota-keys.js.map +1 -1
- package/lib/commands/ota-promote.d.ts +3 -0
- package/lib/commands/ota-promote.d.ts.map +1 -0
- package/lib/commands/ota-promote.js +194 -0
- package/lib/commands/ota-promote.js.map +1 -0
- package/lib/commands/ota-publish.d.ts.map +1 -1
- package/lib/commands/ota-publish.js +108 -38
- package/lib/commands/ota-publish.js.map +1 -1
- package/lib/commands/ota-rollout.d.ts.map +1 -1
- package/lib/commands/ota-rollout.js +201 -171
- package/lib/commands/ota-rollout.js.map +1 -1
- package/lib/commands/quickstart.d.ts.map +1 -1
- package/lib/commands/quickstart.js +110 -8
- package/lib/commands/quickstart.js.map +1 -1
- package/lib/commands/shell.d.ts +28 -0
- package/lib/commands/shell.d.ts.map +1 -0
- package/lib/commands/shell.js +512 -0
- package/lib/commands/shell.js.map +1 -0
- package/lib/index.js +140 -4
- package/lib/index.js.map +1 -1
- package/lib/ui/menu.d.ts +109 -0
- package/lib/ui/menu.d.ts.map +1 -0
- package/lib/ui/menu.js +314 -0
- package/lib/ui/menu.js.map +1 -0
- package/lib/utils/bundle.d.ts.map +1 -1
- package/lib/utils/bundle.js +7 -1
- package/lib/utils/bundle.js.map +1 -1
- package/lib/utils/context.d.ts +88 -0
- package/lib/utils/context.d.ts.map +1 -0
- package/lib/utils/context.js +247 -0
- package/lib/utils/context.js.map +1 -0
- package/lib/utils/credentials.d.ts +16 -0
- package/lib/utils/credentials.d.ts.map +1 -1
- package/lib/utils/credentials.js +14 -3
- package/lib/utils/credentials.js.map +1 -1
- package/lib/utils/guide.d.ts +63 -0
- package/lib/utils/guide.d.ts.map +1 -0
- package/lib/utils/guide.js +189 -0
- package/lib/utils/guide.js.map +1 -0
- package/lib/utils/output.d.ts +96 -0
- package/lib/utils/output.d.ts.map +1 -0
- package/lib/utils/output.js +135 -0
- package/lib/utils/output.js.map +1 -0
- package/lib/utils/prompt.d.ts +80 -6
- package/lib/utils/prompt.d.ts.map +1 -1
- package/lib/utils/prompt.js +184 -20
- package/lib/utils/prompt.js.map +1 -1
- package/lib/utils/provenance.d.ts +30 -0
- package/lib/utils/provenance.d.ts.map +1 -0
- package/lib/utils/provenance.js +157 -0
- package/lib/utils/provenance.js.map +1 -0
- package/lib/utils/resolve.d.ts +81 -0
- package/lib/utils/resolve.d.ts.map +1 -0
- package/lib/utils/resolve.js +139 -0
- package/lib/utils/resolve.js.map +1 -0
- package/lib/utils/sdkBin.d.ts +18 -0
- package/lib/utils/sdkBin.d.ts.map +1 -0
- package/lib/utils/sdkBin.js +76 -0
- package/lib/utils/sdkBin.js.map +1 -0
- package/lib/utils/ui.d.ts +10 -1
- package/lib/utils/ui.d.ts.map +1 -1
- package/lib/utils/ui.js +18 -57
- package/lib/utils/ui.js.map +1 -1
- package/lib/utils/validate.d.ts +62 -0
- package/lib/utils/validate.d.ts.map +1 -0
- package/lib/utils/validate.js +189 -0
- package/lib/utils/validate.js.map +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.GROUPS = void 0;
|
|
7
|
+
exports.commandLabel = commandLabel;
|
|
8
|
+
exports.nextStepHint = nextStepHint;
|
|
9
|
+
exports.renderNextStep = renderNextStep;
|
|
10
|
+
exports.renderAllCommands = renderAllCommands;
|
|
11
|
+
exports.renderGuide = renderGuide;
|
|
12
|
+
exports.contextLineText = contextLineText;
|
|
13
|
+
exports.renderContextLine = renderContextLine;
|
|
14
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
15
|
+
const context_1 = require("./context");
|
|
16
|
+
exports.GROUPS = [
|
|
17
|
+
{
|
|
18
|
+
title: 'SHIP',
|
|
19
|
+
summary: 'get a new bundle in front of devices',
|
|
20
|
+
commands: [
|
|
21
|
+
{ argv: ['ota', 'publish'], desc: 'bundle, upload and publish a release' },
|
|
22
|
+
{ argv: ['ota', 'promote'], desc: 'promote an uploaded bundle to a channel' },
|
|
23
|
+
{ argv: ['ota', 'bundles'], desc: 'list uploaded bundles, newest first' },
|
|
24
|
+
{ argv: ['ota', 'bundle', 'build'], desc: 'build a bundle file for manual upload' },
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
title: 'CONTROL',
|
|
29
|
+
summary: 'change or stop what is already shipping',
|
|
30
|
+
commands: [
|
|
31
|
+
{ argv: ['ota', 'rollout'], desc: 'set the rollout percentage' },
|
|
32
|
+
{ argv: ['ota', 'pause'], desc: 'stop new devices receiving a release' },
|
|
33
|
+
{ argv: ['ota', 'resume'], desc: 'resume a paused release' },
|
|
34
|
+
{ argv: ['ota', 'rollback'], desc: 'revert a release for every device' },
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
title: 'INSPECT',
|
|
39
|
+
summary: 'see what is live and what needs a decision',
|
|
40
|
+
commands: [
|
|
41
|
+
{ argv: ['ota', 'status'], desc: 'what is live, and what needs a decision' },
|
|
42
|
+
{ argv: ['ota', 'releases'], desc: 'list releases and their rollout state' },
|
|
43
|
+
{ argv: ['apps'], desc: 'list your apps and their ids' },
|
|
44
|
+
],
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
title: 'CONFIGURE',
|
|
48
|
+
summary: 'channels, signing keys, and deletions',
|
|
49
|
+
commands: [
|
|
50
|
+
{ argv: ['ota', 'channels'], desc: 'list, create, rename or remove channels' },
|
|
51
|
+
{ argv: ['ota', 'keys'], desc: 'list, register or revoke signing keys' },
|
|
52
|
+
{ argv: ['ota', 'generate-key-pair'], desc: 'create an ed25519 signing key' },
|
|
53
|
+
{ argv: ['ota', 'delete-bundle'], desc: 'delete a bundle permanently' },
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
title: 'SETUP',
|
|
58
|
+
summary: 'sign in, bind the project, wire the native app',
|
|
59
|
+
commands: [
|
|
60
|
+
{ argv: ['quickstart'], desc: 'guided first-release walkthrough' },
|
|
61
|
+
{ argv: ['login'], desc: 'authenticate with an access token' },
|
|
62
|
+
{ argv: ['logout'], desc: 'clear stored credentials' },
|
|
63
|
+
{ argv: ['link'], desc: 'bind this project to an app' },
|
|
64
|
+
{ argv: ['unlink'], desc: 'remove the app binding' },
|
|
65
|
+
{ argv: ['init', 'android'], desc: 'wire the Android app for OTA' },
|
|
66
|
+
{ argv: ['init', 'ios'], desc: 'wire the iOS app for OTA' },
|
|
67
|
+
{ argv: ['doctor'], desc: 'check the project is OTA-ready' },
|
|
68
|
+
{ argv: ['ci', 'init'], desc: 'generate a CI pipeline for publishing' },
|
|
69
|
+
{ argv: ['migrate', 'codepush'], desc: 'migrate from Microsoft CodePush' },
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
];
|
|
73
|
+
/** How a command is written in prose and on the splash. */
|
|
74
|
+
function commandLabel(entry) {
|
|
75
|
+
return `scalebun ${entry.argv.join(' ')}`;
|
|
76
|
+
}
|
|
77
|
+
const cmd = (name, desc, pad = 32) => console.log(` ${chalk_1.default.cyan(name.padEnd(pad))} ${chalk_1.default.dim(desc)}`);
|
|
78
|
+
/**
|
|
79
|
+
* The stage hint as ONE line, for the interactive menu.
|
|
80
|
+
*
|
|
81
|
+
* The printed splash can afford a four-line NEXT block; a menu frame competing
|
|
82
|
+
* with the logo, the status box and five groups cannot. Losing it entirely
|
|
83
|
+
* would be worse — the ladder is what stops a newcomer from picking a command
|
|
84
|
+
* that cannot work yet — so it compresses rather than disappears.
|
|
85
|
+
*/
|
|
86
|
+
function nextStepHint(ctx) {
|
|
87
|
+
const line = (lead, command, why) => chalk_1.default.dim(` ${lead} `) + chalk_1.default.green(command) + chalk_1.default.dim(` ${why}`);
|
|
88
|
+
switch (ctx.stage) {
|
|
89
|
+
case 0:
|
|
90
|
+
return line('start here', 'scalebun quickstart', 'sign in, pick an app, wire it, ship an update');
|
|
91
|
+
case 1:
|
|
92
|
+
return line('next', 'scalebun link', 'bind this project to an app');
|
|
93
|
+
case 2: {
|
|
94
|
+
const p = ctx.platforms.find((x) => ctx.wired[x] === false) ?? ctx.platforms[0] ?? 'android';
|
|
95
|
+
return line('next', `scalebun init ${p}`, 'updates install but never load until this is done');
|
|
96
|
+
}
|
|
97
|
+
case 3:
|
|
98
|
+
return line('next', 'scalebun ota publish', 'bundle, upload and ship your first update');
|
|
99
|
+
default:
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/** The one thing to do next, given the stage. */
|
|
104
|
+
function renderNextStep(ctx) {
|
|
105
|
+
console.log('');
|
|
106
|
+
switch (ctx.stage) {
|
|
107
|
+
case 0:
|
|
108
|
+
console.log(` ${chalk_1.default.bold.white('START HERE')}`);
|
|
109
|
+
console.log(` ${chalk_1.default.green('scalebun quickstart')} ${chalk_1.default.dim('sign in, pick an app, wire it, ship an update')}`);
|
|
110
|
+
console.log('');
|
|
111
|
+
console.log(chalk_1.default.dim(' One guided flow. Everything else becomes relevant once it finishes.'));
|
|
112
|
+
break;
|
|
113
|
+
case 1:
|
|
114
|
+
console.log(` ${chalk_1.default.bold.white('NEXT')}`);
|
|
115
|
+
console.log(` ${chalk_1.default.green('scalebun link')} ${chalk_1.default.dim('bind this project to an app — then --app-id is never needed')}`);
|
|
116
|
+
console.log('');
|
|
117
|
+
cmd('scalebun quickstart', 'or continue the guided flow', 22);
|
|
118
|
+
cmd('scalebun apps', 'list the apps you can publish to', 22);
|
|
119
|
+
break;
|
|
120
|
+
case 2: {
|
|
121
|
+
const p = ctx.platforms.find((x) => ctx.wired[x] === false) ?? ctx.platforms[0] ?? 'android';
|
|
122
|
+
console.log(` ${chalk_1.default.bold.white('NEXT')}`);
|
|
123
|
+
console.log(` ${chalk_1.default.green('scalebun init ' + p)} ${chalk_1.default.dim('wire the native app for OTA, then rebuild')}`);
|
|
124
|
+
console.log('');
|
|
125
|
+
console.log(chalk_1.default.dim(' Updates install but never load until this is done.'));
|
|
126
|
+
cmd('scalebun doctor', 'check what else this project needs', 22);
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
case 3:
|
|
130
|
+
console.log(` ${chalk_1.default.bold.white('NEXT')}`);
|
|
131
|
+
console.log(` ${chalk_1.default.green('scalebun ota publish')} ${chalk_1.default.dim('bundle, upload and ship your first update')}`);
|
|
132
|
+
console.log('');
|
|
133
|
+
// Pad to 32 — the same column renderAllCommands uses, because the
|
|
134
|
+
// grouped surface now prints directly beneath this block.
|
|
135
|
+
if (!ctx.hasSigningKey) {
|
|
136
|
+
cmd('scalebun ota generate-key-pair', 'sign your bundles (recommended)');
|
|
137
|
+
}
|
|
138
|
+
cmd('scalebun doctor', 'verify the project once more');
|
|
139
|
+
break;
|
|
140
|
+
case 4:
|
|
141
|
+
// No hand-holding at stage 4 — the full surface follows.
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/** Every command, grouped by task. Printed at stage 2+ and by `help --all`. */
|
|
146
|
+
function renderAllCommands() {
|
|
147
|
+
for (const g of exports.GROUPS) {
|
|
148
|
+
console.log('');
|
|
149
|
+
console.log(` ${chalk_1.default.bold.white(g.title)}`);
|
|
150
|
+
for (const c of g.commands)
|
|
151
|
+
cmd(commandLabel(c), c.desc);
|
|
152
|
+
}
|
|
153
|
+
console.log('');
|
|
154
|
+
console.log(chalk_1.default.dim(` Every flag: ${chalk_1.default.cyan('scalebun <command> --help')}`));
|
|
155
|
+
console.log('');
|
|
156
|
+
}
|
|
157
|
+
/** The stage-appropriate body of the splash. */
|
|
158
|
+
function renderGuide(ctx) {
|
|
159
|
+
renderNextStep(ctx);
|
|
160
|
+
// Stage 2 — linked — is where the map earns its space. Gating the grouped
|
|
161
|
+
// surface on stage 4 (a release already shipped) was too strict: it withheld
|
|
162
|
+
// the command list from exactly the person walking the setup path, who has
|
|
163
|
+
// committed to the tool and now wants to see what it does. Before stage 2
|
|
164
|
+
// there is no app bound, so most of the surface has nothing to act on and
|
|
165
|
+
// printing it buries the one step that does.
|
|
166
|
+
if (ctx.stage >= 2) {
|
|
167
|
+
renderAllCommands();
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
console.log('');
|
|
171
|
+
console.log(chalk_1.default.dim(` All commands: ${chalk_1.default.cyan('scalebun help --all')}`));
|
|
172
|
+
console.log('');
|
|
173
|
+
}
|
|
174
|
+
/** Context line for the splash and the session header. */
|
|
175
|
+
function contextLineText(ctx) {
|
|
176
|
+
const label = (0, context_1.contextLabel)(ctx);
|
|
177
|
+
if (!label)
|
|
178
|
+
return null;
|
|
179
|
+
const wired = ctx.platforms
|
|
180
|
+
.map((p) => `${p} ${ctx.wired[p] ? chalk_1.default.green('wired') : chalk_1.default.yellow('not wired')}`)
|
|
181
|
+
.join(chalk_1.default.dim(' · '));
|
|
182
|
+
return chalk_1.default.dim(' project ') + chalk_1.default.bold(label) + (wired ? chalk_1.default.dim(' · ') + wired : '');
|
|
183
|
+
}
|
|
184
|
+
function renderContextLine(ctx) {
|
|
185
|
+
const line = contextLineText(ctx);
|
|
186
|
+
if (line)
|
|
187
|
+
console.log(line);
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=guide.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guide.js","sourceRoot":"","sources":["../../src/utils/guide.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Output mode and the exit-code contract.
|
|
3
|
+
*
|
|
4
|
+
* ── Why this exists ─────────────────────────────────────────────────────────
|
|
5
|
+
*
|
|
6
|
+
* Every command printed emoji-decorated chalk and exited 1 for everything.
|
|
7
|
+
* A pipeline could not read back a release id, and — worse — could not tell
|
|
8
|
+
* "object storage flaked, retry this" from "the server rejected the promotion,
|
|
9
|
+
* stop and page someone". Both were `exit(1)`.
|
|
10
|
+
*
|
|
11
|
+
* ── The contract ────────────────────────────────────────────────────────────
|
|
12
|
+
*
|
|
13
|
+
* 0 success
|
|
14
|
+
* 1 usage or local error — bad flag, not signed in, no project. Do not retry.
|
|
15
|
+
* 2 server rejected it — a 4xx. The request was understood and refused.
|
|
16
|
+
* 3 a deliberate gate — a check the operator asked for said no
|
|
17
|
+
* (--fail-on, size budget, preflight gate).
|
|
18
|
+
* 4 transient — network, timeout, 5xx. Retrying is reasonable.
|
|
19
|
+
*
|
|
20
|
+
* 3 is the one that earns its place: it lets CI distinguish "your bundle is
|
|
21
|
+
* 2 MB over budget" from "the API is down", which are the same colour of red
|
|
22
|
+
* today and want opposite responses.
|
|
23
|
+
*/
|
|
24
|
+
export declare enum ExitCode {
|
|
25
|
+
Ok = 0,
|
|
26
|
+
Usage = 1,
|
|
27
|
+
Rejected = 2,
|
|
28
|
+
Gate = 3,
|
|
29
|
+
Network = 4
|
|
30
|
+
}
|
|
31
|
+
/** Enable machine output. Also set from SCALEBUN_JSON=1 for CI without flags. */
|
|
32
|
+
export declare function setJsonMode(on: boolean): void;
|
|
33
|
+
export declare function isJson(): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Print a result.
|
|
36
|
+
*
|
|
37
|
+
* `human` is a function rather than a string so the pretty path costs nothing
|
|
38
|
+
* when it will not run — several commands build tables and spinners that are
|
|
39
|
+
* pure waste under --json.
|
|
40
|
+
*/
|
|
41
|
+
export declare function emit(human: () => void, data: unknown): void;
|
|
42
|
+
/**
|
|
43
|
+
* A command the user is likely to want next.
|
|
44
|
+
*
|
|
45
|
+
* ── Why these are data and not just printed lines ───────────────────────────
|
|
46
|
+
*
|
|
47
|
+
* Commands already ended with a block like
|
|
48
|
+
*
|
|
49
|
+
* Watch it: scalebun ota status
|
|
50
|
+
* Widen it: scalebun ota rollout --percent 100
|
|
51
|
+
* Undo it: scalebun ota rollback
|
|
52
|
+
*
|
|
53
|
+
* which is genuinely the right advice at exactly the right moment — and then
|
|
54
|
+
* asks the reader to retype it. Inside the interactive session that is
|
|
55
|
+
* absurd: the session already knows how to run commands, it just could not
|
|
56
|
+
* see these because they were prose.
|
|
57
|
+
*
|
|
58
|
+
* Recording them alongside the printed text lets the session offer them as a
|
|
59
|
+
* choice, while the plain CLI keeps printing exactly what it printed before.
|
|
60
|
+
* One declaration, so the list a person reads and the list they can select
|
|
61
|
+
* from cannot disagree.
|
|
62
|
+
*/
|
|
63
|
+
export interface NextStep {
|
|
64
|
+
/** Why you would run it: "Watch it", "Undo it". */
|
|
65
|
+
label: string;
|
|
66
|
+
/** Argv, so the session can run it without parsing prose. */
|
|
67
|
+
argv: string[];
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Print the follow-up block AND record it for the session.
|
|
71
|
+
*
|
|
72
|
+
* Silent under --json: the steps belong in the JSON body if a pipeline wants
|
|
73
|
+
* them, not as prose interleaved with a document it is trying to parse.
|
|
74
|
+
*/
|
|
75
|
+
export declare function printNextSteps(steps: NextStep[], chalkish?: (s: string) => string): void;
|
|
76
|
+
/** Drain the recorded steps. The session calls this after each command. */
|
|
77
|
+
export declare function takeNextSteps(): NextStep[];
|
|
78
|
+
/**
|
|
79
|
+
* Fail with a typed exit code.
|
|
80
|
+
*
|
|
81
|
+
* Under --json the error is a JSON object on stdout as well, because a
|
|
82
|
+
* pipeline that has to parse stderr to find out what went wrong is not
|
|
83
|
+
* machine-readable in any useful sense.
|
|
84
|
+
*/
|
|
85
|
+
export declare function fail(message: string, details?: string[], code?: ExitCode): never;
|
|
86
|
+
/**
|
|
87
|
+
* Map a thrown API error onto an exit code.
|
|
88
|
+
*
|
|
89
|
+
* ApiClient formats errors as `API error (HTTP 422): …`, so the status is
|
|
90
|
+
* recoverable from the message without changing every call site. 4xx is the
|
|
91
|
+
* server understanding and refusing; 5xx and socket errors are worth a retry.
|
|
92
|
+
*/
|
|
93
|
+
export declare function codeForError(err: unknown): ExitCode;
|
|
94
|
+
/** Convenience: fail with the code implied by a thrown API error. */
|
|
95
|
+
export declare function failFromError(prefix: string, err: unknown, details?: string[]): never;
|
|
96
|
+
//# sourceMappingURL=output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/utils/output.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,oBAAY,QAAQ;IAClB,EAAE,IAAI;IACN,KAAK,IAAI;IACT,QAAQ,IAAI;IACZ,IAAI,IAAI;IACR,OAAO,IAAI;CACZ;AAID,iFAAiF;AACjF,wBAAgB,WAAW,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAE7C;AAED,wBAAgB,MAAM,IAAI,OAAO,CAEhC;AAED;;;;;;GAMG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,IAAI,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAM3D;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,QAAQ;IACvB,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAID;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAUxF;AAED,2EAA2E;AAC3E,wBAAgB,aAAa,IAAI,QAAQ,EAAE,CAI1C;AAED;;;;;;GAMG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,MAAM,EAAO,EAAE,IAAI,GAAE,QAAyB,GAAG,KAAK,CAUpG;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,QAAQ,CAYnD;AAED,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,GAAE,MAAM,EAAO,GAAG,KAAK,CAGzF"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Output mode and the exit-code contract.
|
|
4
|
+
*
|
|
5
|
+
* ── Why this exists ─────────────────────────────────────────────────────────
|
|
6
|
+
*
|
|
7
|
+
* Every command printed emoji-decorated chalk and exited 1 for everything.
|
|
8
|
+
* A pipeline could not read back a release id, and — worse — could not tell
|
|
9
|
+
* "object storage flaked, retry this" from "the server rejected the promotion,
|
|
10
|
+
* stop and page someone". Both were `exit(1)`.
|
|
11
|
+
*
|
|
12
|
+
* ── The contract ────────────────────────────────────────────────────────────
|
|
13
|
+
*
|
|
14
|
+
* 0 success
|
|
15
|
+
* 1 usage or local error — bad flag, not signed in, no project. Do not retry.
|
|
16
|
+
* 2 server rejected it — a 4xx. The request was understood and refused.
|
|
17
|
+
* 3 a deliberate gate — a check the operator asked for said no
|
|
18
|
+
* (--fail-on, size budget, preflight gate).
|
|
19
|
+
* 4 transient — network, timeout, 5xx. Retrying is reasonable.
|
|
20
|
+
*
|
|
21
|
+
* 3 is the one that earns its place: it lets CI distinguish "your bundle is
|
|
22
|
+
* 2 MB over budget" from "the API is down", which are the same colour of red
|
|
23
|
+
* today and want opposite responses.
|
|
24
|
+
*/
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.ExitCode = void 0;
|
|
27
|
+
exports.setJsonMode = setJsonMode;
|
|
28
|
+
exports.isJson = isJson;
|
|
29
|
+
exports.emit = emit;
|
|
30
|
+
exports.printNextSteps = printNextSteps;
|
|
31
|
+
exports.takeNextSteps = takeNextSteps;
|
|
32
|
+
exports.fail = fail;
|
|
33
|
+
exports.codeForError = codeForError;
|
|
34
|
+
exports.failFromError = failFromError;
|
|
35
|
+
var ExitCode;
|
|
36
|
+
(function (ExitCode) {
|
|
37
|
+
ExitCode[ExitCode["Ok"] = 0] = "Ok";
|
|
38
|
+
ExitCode[ExitCode["Usage"] = 1] = "Usage";
|
|
39
|
+
ExitCode[ExitCode["Rejected"] = 2] = "Rejected";
|
|
40
|
+
ExitCode[ExitCode["Gate"] = 3] = "Gate";
|
|
41
|
+
ExitCode[ExitCode["Network"] = 4] = "Network";
|
|
42
|
+
})(ExitCode || (exports.ExitCode = ExitCode = {}));
|
|
43
|
+
let jsonMode = false;
|
|
44
|
+
/** Enable machine output. Also set from SCALEBUN_JSON=1 for CI without flags. */
|
|
45
|
+
function setJsonMode(on) {
|
|
46
|
+
jsonMode = on;
|
|
47
|
+
}
|
|
48
|
+
function isJson() {
|
|
49
|
+
return jsonMode || process.env.SCALEBUN_JSON === '1';
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Print a result.
|
|
53
|
+
*
|
|
54
|
+
* `human` is a function rather than a string so the pretty path costs nothing
|
|
55
|
+
* when it will not run — several commands build tables and spinners that are
|
|
56
|
+
* pure waste under --json.
|
|
57
|
+
*/
|
|
58
|
+
function emit(human, data) {
|
|
59
|
+
if (isJson()) {
|
|
60
|
+
process.stdout.write(JSON.stringify(data, null, 2) + '\n');
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
human();
|
|
64
|
+
}
|
|
65
|
+
let nextSteps = [];
|
|
66
|
+
/**
|
|
67
|
+
* Print the follow-up block AND record it for the session.
|
|
68
|
+
*
|
|
69
|
+
* Silent under --json: the steps belong in the JSON body if a pipeline wants
|
|
70
|
+
* them, not as prose interleaved with a document it is trying to parse.
|
|
71
|
+
*/
|
|
72
|
+
function printNextSteps(steps, chalkish) {
|
|
73
|
+
nextSteps = steps;
|
|
74
|
+
if (isJson() || !steps.length)
|
|
75
|
+
return;
|
|
76
|
+
const width = steps.reduce((w, s) => Math.max(w, s.label.length), 0);
|
|
77
|
+
console.log('');
|
|
78
|
+
for (const s of steps) {
|
|
79
|
+
const cmd = `scalebun ${s.argv.join(' ')}`;
|
|
80
|
+
console.log(` ${(s.label + ':').padEnd(width + 2)} ${chalkish ? chalkish(cmd) : cmd}`);
|
|
81
|
+
}
|
|
82
|
+
console.log('');
|
|
83
|
+
}
|
|
84
|
+
/** Drain the recorded steps. The session calls this after each command. */
|
|
85
|
+
function takeNextSteps() {
|
|
86
|
+
const out = nextSteps;
|
|
87
|
+
nextSteps = [];
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Fail with a typed exit code.
|
|
92
|
+
*
|
|
93
|
+
* Under --json the error is a JSON object on stdout as well, because a
|
|
94
|
+
* pipeline that has to parse stderr to find out what went wrong is not
|
|
95
|
+
* machine-readable in any useful sense.
|
|
96
|
+
*/
|
|
97
|
+
function fail(message, details = [], code = ExitCode.Usage) {
|
|
98
|
+
if (isJson()) {
|
|
99
|
+
process.stdout.write(JSON.stringify({ ok: false, error: message, details, exitCode: code }, null, 2) + '\n');
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
console.error(`❌ ${message}`);
|
|
103
|
+
for (const d of details)
|
|
104
|
+
console.error(` ${d}`);
|
|
105
|
+
}
|
|
106
|
+
process.exit(code);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Map a thrown API error onto an exit code.
|
|
110
|
+
*
|
|
111
|
+
* ApiClient formats errors as `API error (HTTP 422): …`, so the status is
|
|
112
|
+
* recoverable from the message without changing every call site. 4xx is the
|
|
113
|
+
* server understanding and refusing; 5xx and socket errors are worth a retry.
|
|
114
|
+
*/
|
|
115
|
+
function codeForError(err) {
|
|
116
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
117
|
+
const m = /HTTP (\d{3})/.exec(msg);
|
|
118
|
+
if (m) {
|
|
119
|
+
const status = Number(m[1]);
|
|
120
|
+
if (status >= 500)
|
|
121
|
+
return ExitCode.Network;
|
|
122
|
+
if (status >= 400)
|
|
123
|
+
return ExitCode.Rejected;
|
|
124
|
+
}
|
|
125
|
+
if (/ETIMEDOUT|ECONNRESET|ENOTFOUND|EAI_AGAIN|socket hang up|network/i.test(msg)) {
|
|
126
|
+
return ExitCode.Network;
|
|
127
|
+
}
|
|
128
|
+
return ExitCode.Usage;
|
|
129
|
+
}
|
|
130
|
+
/** Convenience: fail with the code implied by a thrown API error. */
|
|
131
|
+
function failFromError(prefix, err, details = []) {
|
|
132
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
133
|
+
return fail(`${prefix}: ${msg}`, details, codeForError(err));
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/utils/output.ts"],"names":[],"mappings":"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"}
|
package/lib/utils/prompt.d.ts
CHANGED
|
@@ -3,14 +3,88 @@ export declare function canPromptHidden(): boolean;
|
|
|
3
3
|
export declare function promptHidden(query: string): Promise<string>;
|
|
4
4
|
/** Close the shared prompt interface so the process can exit / move on. */
|
|
5
5
|
export declare function closePrompts(): void;
|
|
6
|
-
|
|
7
|
-
export declare function text(query: string, opts?: {
|
|
6
|
+
export interface TextOpts {
|
|
8
7
|
default?: string;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
/** Reject the answer and re-ask; return the reason, or null to accept. */
|
|
9
|
+
validate?: (value: string) => string | null;
|
|
10
|
+
/**
|
|
11
|
+
* Accept an empty answer and return ''. Only for genuinely optional fields —
|
|
12
|
+
* the release note is the one that means it.
|
|
13
|
+
*/
|
|
14
|
+
allowEmpty?: boolean;
|
|
15
|
+
/** One line explaining what a good answer looks like, shown when re-asking. */
|
|
16
|
+
help?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Free-text question with an optional default (shown in parentheses).
|
|
20
|
+
*
|
|
21
|
+
* ── Empty is a question, not an answer ──────────────────────────────────────
|
|
22
|
+
*
|
|
23
|
+
* This used to return '' the moment someone pressed Enter with nothing typed,
|
|
24
|
+
* and every caller then invented its own reaction. `text('App id')` in the
|
|
25
|
+
* publish wizard did `if (!id) process.exit(1)` — a silent exit 1, no message,
|
|
26
|
+
* from a prompt that had just told you it wanted an app id. Others carried the
|
|
27
|
+
* empty string onward until the API rejected a field the user never saw.
|
|
28
|
+
*
|
|
29
|
+
* Pressing Enter at a prompt with no default is almost never a decision; it is
|
|
30
|
+
* someone hurrying, or not knowing what is wanted. So empty now re-asks and
|
|
31
|
+
* explains, and callers with something sensible to fall back on pass a
|
|
32
|
+
* `default` — which is what "Enter means yes" should always have looked like.
|
|
33
|
+
* `allowEmpty` remains for fields that are honestly optional.
|
|
34
|
+
*/
|
|
35
|
+
export declare function text(query: string, opts?: TextOpts): Promise<string>;
|
|
36
|
+
/**
|
|
37
|
+
* Type-this-exact-phrase confirmation, for the destructive commands.
|
|
38
|
+
*
|
|
39
|
+
* Empty and wrong are DIFFERENT mistakes and deserve different answers:
|
|
40
|
+
*
|
|
41
|
+
* empty — cancel. Enter must stay an escape from a prompt that is about to
|
|
42
|
+
* delete a channel or roll back a fleet; re-asking would trap
|
|
43
|
+
* someone whose actual intent was to back out. But say so, rather
|
|
44
|
+
* than printing "Cancelled" and leaving them to guess whether the
|
|
45
|
+
* keystroke registered.
|
|
46
|
+
* wrong — re-ask. A typo in a channel name is not a decision to cancel, and
|
|
47
|
+
* making the operator re-run the whole command mid-incident to fix
|
|
48
|
+
* one character is the worst moment to be pedantic.
|
|
49
|
+
*/
|
|
50
|
+
export declare function confirmPhrase(query: string, expected: string, opts?: {
|
|
51
|
+
caseInsensitive?: boolean;
|
|
13
52
|
}): Promise<boolean>;
|
|
53
|
+
export interface ConfirmOpts {
|
|
54
|
+
/**
|
|
55
|
+
* What Enter means. OMIT IT to require an explicit y or n.
|
|
56
|
+
*
|
|
57
|
+
* Omit it for the decision that commits a flow. `(y/N)` promises that Enter
|
|
58
|
+
* is a safe no, and for "Configure advanced options?" that promise is worth
|
|
59
|
+
* keeping. But at the end of a wizard the user has just chosen a bundle and
|
|
60
|
+
* a rollout percentage, and one stray Enter throws all of it away with
|
|
61
|
+
* "Cancelled — nothing was promoted". Safe, and infuriating: the work is
|
|
62
|
+
* gone and nothing says which keystroke did it.
|
|
63
|
+
*/
|
|
64
|
+
default?: boolean;
|
|
65
|
+
/** Extra guidance shown when the answer is a number. */
|
|
66
|
+
numericHint?: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Yes/no question. Empty input takes the default; anything unrecognised
|
|
70
|
+
* RE-ASKS.
|
|
71
|
+
*
|
|
72
|
+
* ── Why it re-asks ──────────────────────────────────────────────────────────
|
|
73
|
+
*
|
|
74
|
+
* This used to be `return answer === 'y' || answer === 'yes'`, so every input
|
|
75
|
+
* that was not literally yes counted as no. Typing `50` at
|
|
76
|
+
* "Promote v14 to 100% of devices? (y/N)" — a completely reasonable thing to
|
|
77
|
+
* type when you wanted 50% — silently meant "no", and the CLI reported
|
|
78
|
+
* "Cancelled — nothing was promoted" as though the user had declined. The
|
|
79
|
+
* person did not decline. They answered a different question, and the tool
|
|
80
|
+
* discarded the answer and blamed them for it.
|
|
81
|
+
*
|
|
82
|
+
* The same swallow hid `yes please`, `Y ` with a stray space, and a mistyped
|
|
83
|
+
* `t`. Silently reading all of those as "no" is safe for the fleet and awful
|
|
84
|
+
* for the human: the destructive path is protected while the intent is lost
|
|
85
|
+
* without a word.
|
|
86
|
+
*/
|
|
87
|
+
export declare function confirm(query: string, opts?: ConfirmOpts): Promise<boolean>;
|
|
14
88
|
/** Integer question with optional default and min/max validation (loops until valid). */
|
|
15
89
|
export declare function number(query: string, opts?: {
|
|
16
90
|
default?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/utils/prompt.ts"],"names":[],"mappings":"AA4BA,oEAAoE;AACpE,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAiD3D;
|
|
1
|
+
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/utils/prompt.ts"],"names":[],"mappings":"AA4BA,oEAAoE;AACpE,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAiD3D;AAiCD,2EAA2E;AAC3E,wBAAgB,YAAY,IAAI,IAAI,CAKnC;AAmBD,MAAM,WAAW,QAAQ;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC5C;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,+EAA+E;IAC/E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,QAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAsB9E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE;IAAE,eAAe,CAAC,EAAE,OAAO,CAAA;CAAO,GACvC,OAAO,CAAC,OAAO,CAAC,CAclB;AA2BD,MAAM,WAAW,WAAW;IAC1B;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAiCrF;AAED,yFAAyF;AACzF,wBAAsB,MAAM,CAC1B,KAAK,EAAE,MAAM,EACb,IAAI,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAC1D,OAAO,CAAC,MAAM,CAAC,CA4CjB;AAED,MAAM,WAAW,MAAM,CAAC,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,CAAC,CAAC;IACT,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,wBAAsB,MAAM,CAAC,CAAC,EAC5B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,EACpB,IAAI,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAC9B,OAAO,CAAC,CAAC,CAAC,CAKZ"}
|