gh-postplan 0.2.0 → 0.3.1
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 +1 -1
- package/dist/cli.js +1193 -41
- package/package.json +4 -1
- package/skills/gh-postplan/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -52,7 +52,7 @@ npx gh-postplan list
|
|
|
52
52
|
npx gh-postplan delete
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
`delete
|
|
55
|
+
Both commands read the local cache, so the draft list appears immediately. Drafts are shown by their HTML `<title>`. In `delete`, use the arrow keys to move, Space to select multiple drafts, and Enter to delete them. Deleting a draft removes its stable URL and every permanent version.
|
|
56
56
|
|
|
57
57
|
Configuration lives in `~/.config/gh-postplan`. Set `GH_POSTPLAN_REPO=owner/repo` to override the configured repository.
|
|
58
58
|
|
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,1112 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
function __accessProp(key) {
|
|
8
|
+
return this[key];
|
|
9
|
+
}
|
|
10
|
+
var __toESMCache_node;
|
|
11
|
+
var __toESMCache_esm;
|
|
12
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
13
|
+
var canCache = mod != null && typeof mod === "object";
|
|
14
|
+
if (canCache) {
|
|
15
|
+
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
16
|
+
var cached = cache.get(mod);
|
|
17
|
+
if (cached)
|
|
18
|
+
return cached;
|
|
19
|
+
}
|
|
20
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
21
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
22
|
+
if (mod && typeof mod === "object" || typeof mod === "function") {
|
|
23
|
+
for (let key of __getOwnPropNames(mod))
|
|
24
|
+
if (!__hasOwnProp.call(to, key))
|
|
25
|
+
__defProp(to, key, {
|
|
26
|
+
get: __accessProp.bind(mod, key),
|
|
27
|
+
enumerable: true
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
if (canCache)
|
|
31
|
+
cache.set(mod, to);
|
|
32
|
+
return to;
|
|
33
|
+
};
|
|
34
|
+
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
35
|
+
|
|
36
|
+
// node_modules/sisteransi/src/index.js
|
|
37
|
+
var require_src = __commonJS(function(exports, module) {
|
|
38
|
+
var ESC2 = "\x1B";
|
|
39
|
+
var CSI2 = `${ESC2}[`;
|
|
40
|
+
var beep = "\x07";
|
|
41
|
+
var cursor = {
|
|
42
|
+
to(x, y) {
|
|
43
|
+
if (!y)
|
|
44
|
+
return `${CSI2}${x + 1}G`;
|
|
45
|
+
return `${CSI2}${y + 1};${x + 1}H`;
|
|
46
|
+
},
|
|
47
|
+
move(x, y) {
|
|
48
|
+
let ret = "";
|
|
49
|
+
if (x < 0)
|
|
50
|
+
ret += `${CSI2}${-x}D`;
|
|
51
|
+
else if (x > 0)
|
|
52
|
+
ret += `${CSI2}${x}C`;
|
|
53
|
+
if (y < 0)
|
|
54
|
+
ret += `${CSI2}${-y}A`;
|
|
55
|
+
else if (y > 0)
|
|
56
|
+
ret += `${CSI2}${y}B`;
|
|
57
|
+
return ret;
|
|
58
|
+
},
|
|
59
|
+
up: (count = 1) => `${CSI2}${count}A`,
|
|
60
|
+
down: (count = 1) => `${CSI2}${count}B`,
|
|
61
|
+
forward: (count = 1) => `${CSI2}${count}C`,
|
|
62
|
+
backward: (count = 1) => `${CSI2}${count}D`,
|
|
63
|
+
nextLine: (count = 1) => `${CSI2}E`.repeat(count),
|
|
64
|
+
prevLine: (count = 1) => `${CSI2}F`.repeat(count),
|
|
65
|
+
left: `${CSI2}G`,
|
|
66
|
+
hide: `${CSI2}?25l`,
|
|
67
|
+
show: `${CSI2}?25h`,
|
|
68
|
+
save: `${ESC2}7`,
|
|
69
|
+
restore: `${ESC2}8`
|
|
70
|
+
};
|
|
71
|
+
var scroll = {
|
|
72
|
+
up: (count = 1) => `${CSI2}S`.repeat(count),
|
|
73
|
+
down: (count = 1) => `${CSI2}T`.repeat(count)
|
|
74
|
+
};
|
|
75
|
+
var erase = {
|
|
76
|
+
screen: `${CSI2}2J`,
|
|
77
|
+
up: (count = 1) => `${CSI2}1J`.repeat(count),
|
|
78
|
+
down: (count = 1) => `${CSI2}J`.repeat(count),
|
|
79
|
+
line: `${CSI2}2K`,
|
|
80
|
+
lineEnd: `${CSI2}K`,
|
|
81
|
+
lineStart: `${CSI2}1K`,
|
|
82
|
+
lines(count) {
|
|
83
|
+
let clear = "";
|
|
84
|
+
for (let i = 0;i < count; i++)
|
|
85
|
+
clear += this.line + (i < count - 1 ? cursor.up() : "");
|
|
86
|
+
if (count)
|
|
87
|
+
clear += cursor.left;
|
|
88
|
+
return clear;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
module.exports = { cursor, scroll, erase, beep };
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// node_modules/@clack/core/dist/index.mjs
|
|
95
|
+
import { stdout, stdin } from "node:process";
|
|
96
|
+
import * as l from "node:readline";
|
|
97
|
+
import l__default from "node:readline";
|
|
98
|
+
|
|
99
|
+
// node_modules/fast-string-truncated-width/dist/utils.js
|
|
100
|
+
var getCodePointsLength = (() => {
|
|
101
|
+
const SURROGATE_PAIR_RE = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
|
|
102
|
+
return (input) => {
|
|
103
|
+
let surrogatePairsNr = 0;
|
|
104
|
+
SURROGATE_PAIR_RE.lastIndex = 0;
|
|
105
|
+
while (SURROGATE_PAIR_RE.test(input)) {
|
|
106
|
+
surrogatePairsNr += 1;
|
|
107
|
+
}
|
|
108
|
+
return input.length - surrogatePairsNr;
|
|
109
|
+
};
|
|
110
|
+
})();
|
|
111
|
+
var isFullWidth = (x) => {
|
|
112
|
+
return x === 12288 || x >= 65281 && x <= 65376 || x >= 65504 && x <= 65510;
|
|
113
|
+
};
|
|
114
|
+
var isWideNotCJKTNotEmoji = (x) => {
|
|
115
|
+
return x === 8987 || x === 9001 || x >= 12272 && x <= 12287 || x >= 12289 && x <= 12350 || x >= 12441 && x <= 12543 || x >= 12549 && x <= 12591 || x >= 12593 && x <= 12686 || x >= 12688 && x <= 12771 || x >= 12783 && x <= 12830 || x >= 12832 && x <= 12871 || x >= 12880 && x <= 19903 || x >= 65040 && x <= 65049 || x >= 65072 && x <= 65106 || x >= 65108 && x <= 65126 || x >= 65128 && x <= 65131 || x >= 127488 && x <= 127490 || x >= 127504 && x <= 127547 || x >= 127552 && x <= 127560 || x >= 131072 && x <= 196605 || x >= 196608 && x <= 262141;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// node_modules/fast-string-truncated-width/dist/index.js
|
|
119
|
+
var ANSI_RE = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y;
|
|
120
|
+
var CONTROL_RE = /[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y;
|
|
121
|
+
var CJKT_WIDE_RE = /(?:(?![\uFF61-\uFF9F\uFF00-\uFFEF])[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Tangut}]){1,1000}/yu;
|
|
122
|
+
var TAB_RE = /\t{1,1000}/y;
|
|
123
|
+
var EMOJI_RE = /[\u{1F1E6}-\u{1F1FF}]{2}|\u{1F3F4}[\u{E0061}-\u{E007A}]{2}[\u{E0030}-\u{E0039}\u{E0061}-\u{E007A}]{1,3}\u{E007F}|(?:\p{Emoji}\uFE0F\u20E3?|\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation})(?:\u200D(?:\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F\u20E3?))*/yu;
|
|
124
|
+
var LATIN_RE = /(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y;
|
|
125
|
+
var MODIFIER_RE = /\p{M}+/gu;
|
|
126
|
+
var NO_TRUNCATION = { limit: Infinity, ellipsis: "" };
|
|
127
|
+
var getStringTruncatedWidth = (input, truncationOptions = {}, widthOptions = {}) => {
|
|
128
|
+
const LIMIT = truncationOptions.limit ?? Infinity;
|
|
129
|
+
const ELLIPSIS = truncationOptions.ellipsis ?? "";
|
|
130
|
+
const ELLIPSIS_WIDTH = truncationOptions?.ellipsisWidth ?? (ELLIPSIS ? getStringTruncatedWidth(ELLIPSIS, NO_TRUNCATION, widthOptions).width : 0);
|
|
131
|
+
const ANSI_WIDTH = 0;
|
|
132
|
+
const CONTROL_WIDTH = widthOptions.controlWidth ?? 0;
|
|
133
|
+
const TAB_WIDTH = widthOptions.tabWidth ?? 8;
|
|
134
|
+
const EMOJI_WIDTH = widthOptions.emojiWidth ?? 2;
|
|
135
|
+
const FULL_WIDTH_WIDTH = 2;
|
|
136
|
+
const REGULAR_WIDTH = widthOptions.regularWidth ?? 1;
|
|
137
|
+
const WIDE_WIDTH = widthOptions.wideWidth ?? FULL_WIDTH_WIDTH;
|
|
138
|
+
const PARSE_BLOCKS = [
|
|
139
|
+
[LATIN_RE, REGULAR_WIDTH],
|
|
140
|
+
[ANSI_RE, ANSI_WIDTH],
|
|
141
|
+
[CONTROL_RE, CONTROL_WIDTH],
|
|
142
|
+
[TAB_RE, TAB_WIDTH],
|
|
143
|
+
[EMOJI_RE, EMOJI_WIDTH],
|
|
144
|
+
[CJKT_WIDE_RE, WIDE_WIDTH]
|
|
145
|
+
];
|
|
146
|
+
let indexPrev = 0;
|
|
147
|
+
let index = 0;
|
|
148
|
+
let length = input.length;
|
|
149
|
+
let lengthExtra = 0;
|
|
150
|
+
let truncationEnabled = false;
|
|
151
|
+
let truncationIndex = length;
|
|
152
|
+
let truncationLimit = Math.max(0, LIMIT - ELLIPSIS_WIDTH);
|
|
153
|
+
let unmatchedStart = 0;
|
|
154
|
+
let unmatchedEnd = 0;
|
|
155
|
+
let width = 0;
|
|
156
|
+
let widthExtra = 0;
|
|
157
|
+
outer:
|
|
158
|
+
while (true) {
|
|
159
|
+
if (unmatchedEnd > unmatchedStart || index >= length && index > indexPrev) {
|
|
160
|
+
const unmatched = input.slice(unmatchedStart, unmatchedEnd) || input.slice(indexPrev, index);
|
|
161
|
+
lengthExtra = 0;
|
|
162
|
+
for (const char of unmatched.replaceAll(MODIFIER_RE, "")) {
|
|
163
|
+
const codePoint = char.codePointAt(0) || 0;
|
|
164
|
+
if (isFullWidth(codePoint)) {
|
|
165
|
+
widthExtra = FULL_WIDTH_WIDTH;
|
|
166
|
+
} else if (isWideNotCJKTNotEmoji(codePoint)) {
|
|
167
|
+
widthExtra = WIDE_WIDTH;
|
|
168
|
+
} else {
|
|
169
|
+
widthExtra = REGULAR_WIDTH;
|
|
170
|
+
}
|
|
171
|
+
if (width + widthExtra > truncationLimit) {
|
|
172
|
+
truncationIndex = Math.min(truncationIndex, Math.max(unmatchedStart, indexPrev) + lengthExtra);
|
|
173
|
+
}
|
|
174
|
+
if (width + widthExtra > LIMIT) {
|
|
175
|
+
truncationEnabled = true;
|
|
176
|
+
break outer;
|
|
177
|
+
}
|
|
178
|
+
lengthExtra += char.length;
|
|
179
|
+
width += widthExtra;
|
|
180
|
+
}
|
|
181
|
+
unmatchedStart = unmatchedEnd = 0;
|
|
182
|
+
}
|
|
183
|
+
if (index >= length) {
|
|
184
|
+
break outer;
|
|
185
|
+
}
|
|
186
|
+
for (let i = 0, l = PARSE_BLOCKS.length;i < l; i++) {
|
|
187
|
+
const [BLOCK_RE, BLOCK_WIDTH] = PARSE_BLOCKS[i];
|
|
188
|
+
BLOCK_RE.lastIndex = index;
|
|
189
|
+
if (BLOCK_RE.test(input)) {
|
|
190
|
+
lengthExtra = BLOCK_RE === CJKT_WIDE_RE ? getCodePointsLength(input.slice(index, BLOCK_RE.lastIndex)) : BLOCK_RE === EMOJI_RE ? 1 : BLOCK_RE.lastIndex - index;
|
|
191
|
+
widthExtra = lengthExtra * BLOCK_WIDTH;
|
|
192
|
+
if (width + widthExtra > truncationLimit) {
|
|
193
|
+
truncationIndex = Math.min(truncationIndex, index + Math.floor((truncationLimit - width) / BLOCK_WIDTH));
|
|
194
|
+
}
|
|
195
|
+
if (width + widthExtra > LIMIT) {
|
|
196
|
+
truncationEnabled = true;
|
|
197
|
+
break outer;
|
|
198
|
+
}
|
|
199
|
+
width += widthExtra;
|
|
200
|
+
unmatchedStart = indexPrev;
|
|
201
|
+
unmatchedEnd = index;
|
|
202
|
+
index = indexPrev = BLOCK_RE.lastIndex;
|
|
203
|
+
continue outer;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
index += 1;
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
width: truncationEnabled ? truncationLimit : width,
|
|
210
|
+
index: truncationEnabled ? truncationIndex : length,
|
|
211
|
+
truncated: truncationEnabled,
|
|
212
|
+
ellipsed: truncationEnabled && LIMIT >= ELLIPSIS_WIDTH
|
|
213
|
+
};
|
|
214
|
+
};
|
|
215
|
+
var dist_default = getStringTruncatedWidth;
|
|
216
|
+
|
|
217
|
+
// node_modules/fast-string-width/dist/index.js
|
|
218
|
+
var NO_TRUNCATION2 = {
|
|
219
|
+
limit: Infinity,
|
|
220
|
+
ellipsis: "",
|
|
221
|
+
ellipsisWidth: 0
|
|
222
|
+
};
|
|
223
|
+
var fastStringWidth = (input, options = {}) => {
|
|
224
|
+
return dist_default(input, NO_TRUNCATION2, options).width;
|
|
225
|
+
};
|
|
226
|
+
var dist_default2 = fastStringWidth;
|
|
227
|
+
|
|
228
|
+
// node_modules/fast-wrap-ansi/lib/main.js
|
|
229
|
+
var ESC = "\x1B";
|
|
230
|
+
var CSI = "";
|
|
231
|
+
var END_CODE = 39;
|
|
232
|
+
var ANSI_ESCAPE_BELL = "\x07";
|
|
233
|
+
var ANSI_CSI = "[";
|
|
234
|
+
var ANSI_OSC = "]";
|
|
235
|
+
var ANSI_SGR_TERMINATOR = "m";
|
|
236
|
+
var ANSI_ESCAPE_LINK = `${ANSI_OSC}8;;`;
|
|
237
|
+
var GROUP_REGEX = new RegExp(`(?:\\${ANSI_CSI}(?<code>\\d+)m|\\${ANSI_ESCAPE_LINK}(?<uri>.*)${ANSI_ESCAPE_BELL})`, "y");
|
|
238
|
+
var getClosingCode = (openingCode) => {
|
|
239
|
+
if (openingCode >= 30 && openingCode <= 37)
|
|
240
|
+
return 39;
|
|
241
|
+
if (openingCode >= 90 && openingCode <= 97)
|
|
242
|
+
return 39;
|
|
243
|
+
if (openingCode >= 40 && openingCode <= 47)
|
|
244
|
+
return 49;
|
|
245
|
+
if (openingCode >= 100 && openingCode <= 107)
|
|
246
|
+
return 49;
|
|
247
|
+
if (openingCode === 1 || openingCode === 2)
|
|
248
|
+
return 22;
|
|
249
|
+
if (openingCode === 3)
|
|
250
|
+
return 23;
|
|
251
|
+
if (openingCode === 4)
|
|
252
|
+
return 24;
|
|
253
|
+
if (openingCode === 7)
|
|
254
|
+
return 27;
|
|
255
|
+
if (openingCode === 8)
|
|
256
|
+
return 28;
|
|
257
|
+
if (openingCode === 9)
|
|
258
|
+
return 29;
|
|
259
|
+
if (openingCode === 0)
|
|
260
|
+
return 0;
|
|
261
|
+
return;
|
|
262
|
+
};
|
|
263
|
+
var wrapAnsiCode = (code) => `${ESC}${ANSI_CSI}${code}${ANSI_SGR_TERMINATOR}`;
|
|
264
|
+
var wrapAnsiHyperlink = (url) => `${ESC}${ANSI_ESCAPE_LINK}${url}${ANSI_ESCAPE_BELL}`;
|
|
265
|
+
var wrapWord = (rows, word, columns) => {
|
|
266
|
+
const characters = word[Symbol.iterator]();
|
|
267
|
+
let isInsideEscape = false;
|
|
268
|
+
let isInsideLinkEscape = false;
|
|
269
|
+
let lastRow = rows.at(-1);
|
|
270
|
+
let visible = lastRow === undefined ? 0 : dist_default2(lastRow);
|
|
271
|
+
let currentCharacter = characters.next();
|
|
272
|
+
let nextCharacter = characters.next();
|
|
273
|
+
let rawCharacterIndex = 0;
|
|
274
|
+
while (!currentCharacter.done) {
|
|
275
|
+
const character = currentCharacter.value;
|
|
276
|
+
const characterLength = dist_default2(character);
|
|
277
|
+
if (visible + characterLength <= columns) {
|
|
278
|
+
rows[rows.length - 1] += character;
|
|
279
|
+
} else {
|
|
280
|
+
rows.push(character);
|
|
281
|
+
visible = 0;
|
|
282
|
+
}
|
|
283
|
+
if (character === ESC || character === CSI) {
|
|
284
|
+
isInsideEscape = true;
|
|
285
|
+
isInsideLinkEscape = word.startsWith(ANSI_ESCAPE_LINK, rawCharacterIndex + 1);
|
|
286
|
+
}
|
|
287
|
+
if (isInsideEscape) {
|
|
288
|
+
if (isInsideLinkEscape) {
|
|
289
|
+
if (character === ANSI_ESCAPE_BELL) {
|
|
290
|
+
isInsideEscape = false;
|
|
291
|
+
isInsideLinkEscape = false;
|
|
292
|
+
}
|
|
293
|
+
} else if (character === ANSI_SGR_TERMINATOR) {
|
|
294
|
+
isInsideEscape = false;
|
|
295
|
+
}
|
|
296
|
+
} else {
|
|
297
|
+
visible += characterLength;
|
|
298
|
+
if (visible === columns && !nextCharacter.done) {
|
|
299
|
+
rows.push("");
|
|
300
|
+
visible = 0;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
currentCharacter = nextCharacter;
|
|
304
|
+
nextCharacter = characters.next();
|
|
305
|
+
rawCharacterIndex += character.length;
|
|
306
|
+
}
|
|
307
|
+
lastRow = rows.at(-1);
|
|
308
|
+
if (!visible && lastRow !== undefined && lastRow.length && rows.length > 1) {
|
|
309
|
+
rows[rows.length - 2] += rows.pop();
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
var stringVisibleTrimSpacesRight = (string) => {
|
|
313
|
+
const words = string.split(" ");
|
|
314
|
+
let last = words.length;
|
|
315
|
+
while (last) {
|
|
316
|
+
if (dist_default2(words[last - 1])) {
|
|
317
|
+
break;
|
|
318
|
+
}
|
|
319
|
+
last--;
|
|
320
|
+
}
|
|
321
|
+
if (last === words.length) {
|
|
322
|
+
return string;
|
|
323
|
+
}
|
|
324
|
+
return words.slice(0, last).join(" ") + words.slice(last).join("");
|
|
325
|
+
};
|
|
326
|
+
var exec = (string, columns, options = {}) => {
|
|
327
|
+
if (options.trim !== false && string.trim() === "") {
|
|
328
|
+
return "";
|
|
329
|
+
}
|
|
330
|
+
let returnValue = "";
|
|
331
|
+
let escapeCode;
|
|
332
|
+
let escapeUrl;
|
|
333
|
+
const words = string.split(" ");
|
|
334
|
+
let rows = [""];
|
|
335
|
+
let rowLength = 0;
|
|
336
|
+
for (let index = 0;index < words.length; index++) {
|
|
337
|
+
const word = words[index];
|
|
338
|
+
if (options.trim !== false) {
|
|
339
|
+
const row = rows.at(-1) ?? "";
|
|
340
|
+
const trimmed = row.trimStart();
|
|
341
|
+
if (row.length !== trimmed.length) {
|
|
342
|
+
rows[rows.length - 1] = trimmed;
|
|
343
|
+
rowLength = dist_default2(trimmed);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
if (index !== 0) {
|
|
347
|
+
if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) {
|
|
348
|
+
rows.push("");
|
|
349
|
+
rowLength = 0;
|
|
350
|
+
}
|
|
351
|
+
if (rowLength || options.trim === false) {
|
|
352
|
+
rows[rows.length - 1] += " ";
|
|
353
|
+
rowLength++;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
const wordLength = dist_default2(word);
|
|
357
|
+
if (options.hard && wordLength > columns) {
|
|
358
|
+
const remainingColumns = columns - rowLength;
|
|
359
|
+
const breaksStartingThisLine = 1 + Math.floor((wordLength - remainingColumns - 1) / columns);
|
|
360
|
+
const breaksStartingNextLine = Math.floor((wordLength - 1) / columns);
|
|
361
|
+
if (breaksStartingNextLine < breaksStartingThisLine) {
|
|
362
|
+
rows.push("");
|
|
363
|
+
}
|
|
364
|
+
wrapWord(rows, word, columns);
|
|
365
|
+
rowLength = dist_default2(rows.at(-1) ?? "");
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
if (rowLength + wordLength > columns && rowLength && wordLength) {
|
|
369
|
+
if (options.wordWrap === false && rowLength < columns) {
|
|
370
|
+
wrapWord(rows, word, columns);
|
|
371
|
+
rowLength = dist_default2(rows.at(-1) ?? "");
|
|
372
|
+
continue;
|
|
373
|
+
}
|
|
374
|
+
rows.push("");
|
|
375
|
+
rowLength = 0;
|
|
376
|
+
}
|
|
377
|
+
if (rowLength + wordLength > columns && options.wordWrap === false) {
|
|
378
|
+
wrapWord(rows, word, columns);
|
|
379
|
+
rowLength = dist_default2(rows.at(-1) ?? "");
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
rows[rows.length - 1] += word;
|
|
383
|
+
rowLength += wordLength;
|
|
384
|
+
}
|
|
385
|
+
if (options.trim !== false) {
|
|
386
|
+
rows = rows.map((row) => stringVisibleTrimSpacesRight(row));
|
|
387
|
+
}
|
|
388
|
+
const preString = rows.join(`
|
|
389
|
+
`);
|
|
390
|
+
let inSurrogate = false;
|
|
391
|
+
for (let i = 0;i < preString.length; i++) {
|
|
392
|
+
const character = preString[i];
|
|
393
|
+
returnValue += character;
|
|
394
|
+
if (!inSurrogate) {
|
|
395
|
+
inSurrogate = character >= "\uD800" && character <= "\uDBFF";
|
|
396
|
+
if (inSurrogate) {
|
|
397
|
+
continue;
|
|
398
|
+
}
|
|
399
|
+
} else {
|
|
400
|
+
inSurrogate = false;
|
|
401
|
+
}
|
|
402
|
+
if (character === ESC || character === CSI) {
|
|
403
|
+
GROUP_REGEX.lastIndex = i + 1;
|
|
404
|
+
const groupsResult = GROUP_REGEX.exec(preString);
|
|
405
|
+
const groups = groupsResult?.groups;
|
|
406
|
+
if (groups?.code !== undefined) {
|
|
407
|
+
const code = Number.parseFloat(groups.code);
|
|
408
|
+
escapeCode = code === END_CODE ? undefined : code;
|
|
409
|
+
} else if (groups?.uri !== undefined) {
|
|
410
|
+
escapeUrl = groups.uri.length === 0 ? undefined : groups.uri;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
if (preString[i + 1] === `
|
|
414
|
+
`) {
|
|
415
|
+
if (escapeUrl) {
|
|
416
|
+
returnValue += wrapAnsiHyperlink("");
|
|
417
|
+
}
|
|
418
|
+
const closingCode = escapeCode ? getClosingCode(escapeCode) : undefined;
|
|
419
|
+
if (escapeCode && closingCode) {
|
|
420
|
+
returnValue += wrapAnsiCode(closingCode);
|
|
421
|
+
}
|
|
422
|
+
} else if (character === `
|
|
423
|
+
`) {
|
|
424
|
+
if (escapeCode && getClosingCode(escapeCode)) {
|
|
425
|
+
returnValue += wrapAnsiCode(escapeCode);
|
|
426
|
+
}
|
|
427
|
+
if (escapeUrl) {
|
|
428
|
+
returnValue += wrapAnsiHyperlink(escapeUrl);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
return returnValue;
|
|
433
|
+
};
|
|
434
|
+
var CRLF_OR_LF = /\r?\n/;
|
|
435
|
+
function wrapAnsi(string, columns, options) {
|
|
436
|
+
return String(string).normalize().split(CRLF_OR_LF).map((line) => exec(line, columns, options)).join(`
|
|
437
|
+
`);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// node_modules/@clack/core/dist/index.mjs
|
|
441
|
+
var import_sisteransi = __toESM(require_src(), 1);
|
|
442
|
+
import { ReadStream } from "node:tty";
|
|
443
|
+
function findCursor(s, o, l2) {
|
|
444
|
+
if (!l2.some((r) => !r.disabled))
|
|
445
|
+
return s;
|
|
446
|
+
const t = s + o, n = Math.max(l2.length - 1, 0), e = t < 0 ? n : t > n ? 0 : t;
|
|
447
|
+
return l2[e]?.disabled ? findCursor(e, o < 0 ? -1 : 1, l2) : e;
|
|
448
|
+
}
|
|
449
|
+
var a$1 = ["up", "down", "left", "right", "space", "enter", "cancel"];
|
|
450
|
+
var t = [
|
|
451
|
+
"January",
|
|
452
|
+
"February",
|
|
453
|
+
"March",
|
|
454
|
+
"April",
|
|
455
|
+
"May",
|
|
456
|
+
"June",
|
|
457
|
+
"July",
|
|
458
|
+
"August",
|
|
459
|
+
"September",
|
|
460
|
+
"October",
|
|
461
|
+
"November",
|
|
462
|
+
"December"
|
|
463
|
+
];
|
|
464
|
+
var settings = {
|
|
465
|
+
actions: new Set(a$1),
|
|
466
|
+
aliases: /* @__PURE__ */ new Map([
|
|
467
|
+
["k", "up"],
|
|
468
|
+
["j", "down"],
|
|
469
|
+
["h", "left"],
|
|
470
|
+
["l", "right"],
|
|
471
|
+
["\x03", "cancel"],
|
|
472
|
+
["escape", "cancel"]
|
|
473
|
+
]),
|
|
474
|
+
messages: {
|
|
475
|
+
cancel: "Canceled",
|
|
476
|
+
error: "Something went wrong"
|
|
477
|
+
},
|
|
478
|
+
withGuide: true,
|
|
479
|
+
date: {
|
|
480
|
+
monthNames: [...t],
|
|
481
|
+
messages: {
|
|
482
|
+
required: "Please enter a valid date",
|
|
483
|
+
invalidMonth: "There are only 12 months in a year",
|
|
484
|
+
invalidDay: (n, e) => `There are only ${n} days in ${e}`,
|
|
485
|
+
afterMin: (n) => `Date must be on or after ${n.toISOString().slice(0, 10)}`,
|
|
486
|
+
beforeMax: (n) => `Date must be on or before ${n.toISOString().slice(0, 10)}`
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
};
|
|
490
|
+
function isActionKey(n, e) {
|
|
491
|
+
if (typeof n == "string")
|
|
492
|
+
return settings.aliases.get(n) === e;
|
|
493
|
+
for (const s of n)
|
|
494
|
+
if (s !== undefined && isActionKey(s, e))
|
|
495
|
+
return true;
|
|
496
|
+
return false;
|
|
497
|
+
}
|
|
498
|
+
function diffLines(i, s) {
|
|
499
|
+
if (i === s)
|
|
500
|
+
return;
|
|
501
|
+
const e = i.split(`
|
|
502
|
+
`), t2 = s.split(`
|
|
503
|
+
`), r = Math.max(e.length, t2.length), f = [];
|
|
504
|
+
for (let n = 0;n < r; n++)
|
|
505
|
+
e[n] !== t2[n] && f.push(n);
|
|
506
|
+
return {
|
|
507
|
+
lines: f,
|
|
508
|
+
numLinesBefore: e.length,
|
|
509
|
+
numLinesAfter: t2.length,
|
|
510
|
+
numLines: r
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
var R = globalThis.process.platform.startsWith("win");
|
|
514
|
+
var CANCEL_SYMBOL = Symbol("clack:cancel");
|
|
515
|
+
function isCancel(e) {
|
|
516
|
+
return e === CANCEL_SYMBOL;
|
|
517
|
+
}
|
|
518
|
+
function setRawMode(e, r) {
|
|
519
|
+
const o = e;
|
|
520
|
+
o.isTTY && o.setRawMode(r);
|
|
521
|
+
}
|
|
522
|
+
function block({
|
|
523
|
+
input: e = stdin,
|
|
524
|
+
output: r = stdout,
|
|
525
|
+
overwrite: o = true,
|
|
526
|
+
hideCursor: t2 = true
|
|
527
|
+
} = {}) {
|
|
528
|
+
const s = l.createInterface({
|
|
529
|
+
input: e,
|
|
530
|
+
output: r,
|
|
531
|
+
prompt: "",
|
|
532
|
+
tabSize: 1
|
|
533
|
+
});
|
|
534
|
+
l.emitKeypressEvents(e, s), e instanceof ReadStream && e.isTTY && e.setRawMode(true);
|
|
535
|
+
const n = (f, { name: a, sequence: p }) => {
|
|
536
|
+
const c = String(f);
|
|
537
|
+
if (isActionKey([c, a, p], "cancel")) {
|
|
538
|
+
t2 && r.write(import_sisteransi.cursor.show), process.exit(0);
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
if (!o)
|
|
542
|
+
return;
|
|
543
|
+
const i = a === "return" ? 0 : -1, m = a === "return" ? -1 : 0;
|
|
544
|
+
l.moveCursor(r, i, m, () => {
|
|
545
|
+
l.clearLine(r, 1, () => {
|
|
546
|
+
e.once("keypress", n);
|
|
547
|
+
});
|
|
548
|
+
});
|
|
549
|
+
};
|
|
550
|
+
return t2 && r.write(import_sisteransi.cursor.hide), e.once("keypress", n), () => {
|
|
551
|
+
e.off("keypress", n), t2 && r.write(import_sisteransi.cursor.show), e instanceof ReadStream && e.isTTY && !R && e.setRawMode(false), s.terminal = false, s.close();
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
var getColumns = (e) => ("columns" in e) && typeof e.columns == "number" ? e.columns : 80;
|
|
555
|
+
var getRows = (e) => ("rows" in e) && typeof e.rows == "number" ? e.rows : 20;
|
|
556
|
+
function wrapTextWithPrefix(e, r, o, t2 = o, s = o, n) {
|
|
557
|
+
const f = getColumns(e ?? stdout);
|
|
558
|
+
return wrapAnsi(r, f - o.length, {
|
|
559
|
+
hard: true,
|
|
560
|
+
trim: false
|
|
561
|
+
}).split(`
|
|
562
|
+
`).map((c, i, m) => {
|
|
563
|
+
const d = n ? n(c, i) : c;
|
|
564
|
+
return i === 0 ? `${t2}${d}` : i === m.length - 1 ? `${s}${d}` : `${o}${d}`;
|
|
565
|
+
}).join(`
|
|
566
|
+
`);
|
|
567
|
+
}
|
|
568
|
+
function runValidation(e, n) {
|
|
569
|
+
if ("~standard" in e) {
|
|
570
|
+
const a = e["~standard"].validate(n);
|
|
571
|
+
if (a instanceof Promise)
|
|
572
|
+
throw new TypeError("Schema validation must be synchronous. Update `validate()` and remove any asynchronous logic.");
|
|
573
|
+
return a.issues?.at(0)?.message;
|
|
574
|
+
}
|
|
575
|
+
return e(n);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
class V {
|
|
579
|
+
input;
|
|
580
|
+
output;
|
|
581
|
+
_abortSignal;
|
|
582
|
+
rl;
|
|
583
|
+
opts;
|
|
584
|
+
_render;
|
|
585
|
+
_track = false;
|
|
586
|
+
_prevFrame = "";
|
|
587
|
+
_subscribers = /* @__PURE__ */ new Map;
|
|
588
|
+
_cursor = 0;
|
|
589
|
+
state = "initial";
|
|
590
|
+
error = "";
|
|
591
|
+
value;
|
|
592
|
+
userInput = "";
|
|
593
|
+
constructor(t2, e = true) {
|
|
594
|
+
const { input: i = stdin, output: n = stdout, render: s, signal: r, ...o } = t2;
|
|
595
|
+
this.opts = o, this.onKeypress = this.onKeypress.bind(this), this.close = this.close.bind(this), this.render = this.render.bind(this), this._render = s.bind(this), this._track = e, this._abortSignal = r, this.input = i, this.output = n;
|
|
596
|
+
}
|
|
597
|
+
unsubscribe() {
|
|
598
|
+
this._subscribers.clear();
|
|
599
|
+
}
|
|
600
|
+
setSubscriber(t2, e) {
|
|
601
|
+
const i = this._subscribers.get(t2) ?? [];
|
|
602
|
+
i.push(e), this._subscribers.set(t2, i);
|
|
603
|
+
}
|
|
604
|
+
on(t2, e) {
|
|
605
|
+
this.setSubscriber(t2, { cb: e });
|
|
606
|
+
}
|
|
607
|
+
once(t2, e) {
|
|
608
|
+
this.setSubscriber(t2, { cb: e, once: true });
|
|
609
|
+
}
|
|
610
|
+
emit(t2, ...e) {
|
|
611
|
+
const i = this._subscribers.get(t2) ?? [], n = [];
|
|
612
|
+
for (const s of i)
|
|
613
|
+
s.cb(...e), s.once && n.push(() => i.splice(i.indexOf(s), 1));
|
|
614
|
+
for (const s of n)
|
|
615
|
+
s();
|
|
616
|
+
}
|
|
617
|
+
prompt() {
|
|
618
|
+
return new Promise((t2) => {
|
|
619
|
+
if (this._abortSignal) {
|
|
620
|
+
if (this._abortSignal.aborted)
|
|
621
|
+
return this.state = "cancel", this.close(), t2(CANCEL_SYMBOL);
|
|
622
|
+
this._abortSignal.addEventListener("abort", () => {
|
|
623
|
+
this.state = "cancel", this.close();
|
|
624
|
+
}, { once: true });
|
|
625
|
+
}
|
|
626
|
+
this.rl = l__default.createInterface({
|
|
627
|
+
input: this.input,
|
|
628
|
+
tabSize: 2,
|
|
629
|
+
prompt: "",
|
|
630
|
+
escapeCodeTimeout: 50,
|
|
631
|
+
terminal: true
|
|
632
|
+
}), this.rl.prompt(), this.opts.initialUserInput !== undefined && this._setUserInput(this.opts.initialUserInput, true), this.input.on("keypress", this.onKeypress), setRawMode(this.input, true), this.output.on("resize", this.render), this.render(), this.once("submit", () => {
|
|
633
|
+
this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), setRawMode(this.input, false), t2(this.value);
|
|
634
|
+
}), this.once("cancel", () => {
|
|
635
|
+
this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), setRawMode(this.input, false), t2(CANCEL_SYMBOL);
|
|
636
|
+
});
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
_isActionKey(t2, e) {
|
|
640
|
+
return t2 === "\t";
|
|
641
|
+
}
|
|
642
|
+
_shouldSubmit(t2, e) {
|
|
643
|
+
return true;
|
|
644
|
+
}
|
|
645
|
+
_setValue(t2) {
|
|
646
|
+
this.value = t2, this.emit("value", this.value);
|
|
647
|
+
}
|
|
648
|
+
_setUserInput(t2, e) {
|
|
649
|
+
this.userInput = t2 ?? "", this.emit("userInput", this.userInput), e && this._track && this.rl && (this.rl.write(this.userInput), this._cursor = this.rl.cursor);
|
|
650
|
+
}
|
|
651
|
+
_clearUserInput() {
|
|
652
|
+
this.rl?.write(null, { ctrl: true, name: "u" }), this._setUserInput("");
|
|
653
|
+
}
|
|
654
|
+
onKeypress(t2, e) {
|
|
655
|
+
if (this._track && e.name !== "return" && (e.name && this._isActionKey(t2, e) && this.rl?.write(null, { ctrl: true, name: "h" }), this._cursor = this.rl?.cursor ?? 0, this._setUserInput(this.rl?.line)), this.state === "error" && (this.state = "active"), e?.name && (!this._track && settings.aliases.has(e.name) && this.emit("cursor", settings.aliases.get(e.name)), settings.actions.has(e.name) && this.emit("cursor", e.name)), t2 && (t2.toLowerCase() === "y" || t2.toLowerCase() === "n") && this.emit("confirm", t2.toLowerCase() === "y"), this.emit("key", t2, e), e?.name === "return" && this._shouldSubmit(t2, e)) {
|
|
656
|
+
if (this.opts.validate) {
|
|
657
|
+
const i = runValidation(this.opts.validate, this.value);
|
|
658
|
+
i && (this.error = i instanceof Error ? i.message : i, this.state = "error", this.rl?.write(this.userInput));
|
|
659
|
+
}
|
|
660
|
+
this.state !== "error" && (this.state = "submit");
|
|
661
|
+
}
|
|
662
|
+
isActionKey([t2, e?.name, e?.sequence], "cancel") && (this.state = "cancel"), (this.state === "submit" || this.state === "cancel") && this.emit("finalize"), this.render(), (this.state === "submit" || this.state === "cancel") && this.close();
|
|
663
|
+
}
|
|
664
|
+
close() {
|
|
665
|
+
this.input.unpipe(), this.input.removeListener("keypress", this.onKeypress), this.output.write(`
|
|
666
|
+
`), setRawMode(this.input, false), this.rl?.close(), this.rl = undefined, this.emit(`${this.state}`, this.value), this.unsubscribe();
|
|
667
|
+
}
|
|
668
|
+
restoreCursor() {
|
|
669
|
+
const t2 = wrapAnsi(this._prevFrame, process.stdout.columns, { hard: true, trim: false }).split(`
|
|
670
|
+
`).length - 1;
|
|
671
|
+
this.output.write(import_sisteransi.cursor.move(-999, t2 * -1));
|
|
672
|
+
}
|
|
673
|
+
render() {
|
|
674
|
+
const t2 = wrapAnsi(this._render(this) ?? "", process.stdout.columns, {
|
|
675
|
+
hard: true,
|
|
676
|
+
trim: false
|
|
677
|
+
});
|
|
678
|
+
if (t2 !== this._prevFrame) {
|
|
679
|
+
if (this.state === "initial")
|
|
680
|
+
this.output.write(import_sisteransi.cursor.hide);
|
|
681
|
+
else {
|
|
682
|
+
const e = diffLines(this._prevFrame, t2), i = getRows(this.output);
|
|
683
|
+
if (this.restoreCursor(), e) {
|
|
684
|
+
const n = Math.max(0, e.numLinesAfter - i), s = Math.max(0, e.numLinesBefore - i);
|
|
685
|
+
let r = e.lines.find((o) => o >= n);
|
|
686
|
+
if (r === undefined) {
|
|
687
|
+
this._prevFrame = t2;
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
if (e.lines.length === 1) {
|
|
691
|
+
this.output.write(import_sisteransi.cursor.move(0, r - s)), this.output.write(import_sisteransi.erase.lines(1));
|
|
692
|
+
const o = t2.split(`
|
|
693
|
+
`);
|
|
694
|
+
this.output.write(o[r]), this._prevFrame = t2, this.output.write(import_sisteransi.cursor.move(0, o.length - r - 1));
|
|
695
|
+
return;
|
|
696
|
+
} else if (e.lines.length > 1) {
|
|
697
|
+
if (n < s)
|
|
698
|
+
r = n;
|
|
699
|
+
else {
|
|
700
|
+
const h = r - s;
|
|
701
|
+
h > 0 && this.output.write(import_sisteransi.cursor.move(0, h));
|
|
702
|
+
}
|
|
703
|
+
this.output.write(import_sisteransi.erase.down());
|
|
704
|
+
const f = t2.split(`
|
|
705
|
+
`).slice(r);
|
|
706
|
+
this.output.write(f.join(`
|
|
707
|
+
`)), this._prevFrame = t2;
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
this.output.write(import_sisteransi.erase.down());
|
|
712
|
+
}
|
|
713
|
+
this.output.write(t2), this.state === "initial" && (this.state = "active"), this._prevFrame = t2;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
class a extends V {
|
|
718
|
+
options;
|
|
719
|
+
cursor = 0;
|
|
720
|
+
get _value() {
|
|
721
|
+
return this.options[this.cursor]?.value;
|
|
722
|
+
}
|
|
723
|
+
get _enabledOptions() {
|
|
724
|
+
return this.options.filter((e) => e.disabled !== true);
|
|
725
|
+
}
|
|
726
|
+
toggleAll() {
|
|
727
|
+
const e = this._enabledOptions, i = this.value !== undefined && this.value.length === e.length;
|
|
728
|
+
this.value = i ? [] : e.map((t2) => t2.value);
|
|
729
|
+
}
|
|
730
|
+
toggleInvert() {
|
|
731
|
+
const e = this.value;
|
|
732
|
+
if (!e)
|
|
733
|
+
return;
|
|
734
|
+
const i = this._enabledOptions.filter((t2) => !e.includes(t2.value));
|
|
735
|
+
this.value = i.map((t2) => t2.value);
|
|
736
|
+
}
|
|
737
|
+
toggleValue() {
|
|
738
|
+
this.value === undefined && (this.value = []);
|
|
739
|
+
const e = this.value.includes(this._value);
|
|
740
|
+
this.value = e ? this.value.filter((i) => i !== this._value) : [...this.value, this._value];
|
|
741
|
+
}
|
|
742
|
+
constructor(e) {
|
|
743
|
+
super(e, false), this.options = e.options, this.value = [...e.initialValues ?? []];
|
|
744
|
+
const i = Math.max(this.options.findIndex(({ value: t2 }) => t2 === e.cursorAt), 0);
|
|
745
|
+
this.cursor = this.options[i]?.disabled ? findCursor(i, 1, this.options) : i, this.on("key", (t2, l2) => {
|
|
746
|
+
l2.name === "a" && this.toggleAll(), l2.name === "i" && this.toggleInvert();
|
|
747
|
+
}), this.on("cursor", (t2) => {
|
|
748
|
+
switch (t2) {
|
|
749
|
+
case "left":
|
|
750
|
+
case "up":
|
|
751
|
+
this.cursor = findCursor(this.cursor, -1, this.options);
|
|
752
|
+
break;
|
|
753
|
+
case "down":
|
|
754
|
+
case "right":
|
|
755
|
+
this.cursor = findCursor(this.cursor, 1, this.options);
|
|
756
|
+
break;
|
|
757
|
+
case "space":
|
|
758
|
+
this.toggleValue();
|
|
759
|
+
break;
|
|
760
|
+
}
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
// node_modules/@clack/prompts/dist/index.mjs
|
|
766
|
+
import { styleText, stripVTControlCharacters } from "node:util";
|
|
767
|
+
import process$1 from "node:process";
|
|
768
|
+
var import_sisteransi2 = __toESM(require_src(), 1);
|
|
769
|
+
function isUnicodeSupported() {
|
|
770
|
+
if (process$1.platform !== "win32") {
|
|
771
|
+
return process$1.env.TERM !== "linux";
|
|
772
|
+
}
|
|
773
|
+
return Boolean(process$1.env.CI) || Boolean(process$1.env.WT_SESSION) || Boolean(process$1.env.TERMINUS_SUBLIME) || process$1.env.ConEmuTask === "{cmd::Cmder}" || process$1.env.TERM_PROGRAM === "Terminus-Sublime" || process$1.env.TERM_PROGRAM === "vscode" || process$1.env.TERM === "xterm-256color" || process$1.env.TERM === "alacritty" || process$1.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
|
|
774
|
+
}
|
|
775
|
+
var unicode = isUnicodeSupported();
|
|
776
|
+
var isCI = () => process.env.CI === "true";
|
|
777
|
+
var unicodeOr = (o, e) => unicode ? o : e;
|
|
778
|
+
var S_STEP_ACTIVE = unicodeOr("◆", "*");
|
|
779
|
+
var S_STEP_CANCEL = unicodeOr("■", "x");
|
|
780
|
+
var S_STEP_ERROR = unicodeOr("▲", "x");
|
|
781
|
+
var S_STEP_SUBMIT = unicodeOr("◇", "o");
|
|
782
|
+
var S_BAR_START = unicodeOr("┌", "T");
|
|
783
|
+
var S_BAR = unicodeOr("│", "|");
|
|
784
|
+
var S_BAR_END = unicodeOr("└", "—");
|
|
785
|
+
var S_BAR_START_RIGHT = unicodeOr("┐", "T");
|
|
786
|
+
var S_BAR_END_RIGHT = unicodeOr("┘", "—");
|
|
787
|
+
var S_RADIO_ACTIVE = unicodeOr("●", ">");
|
|
788
|
+
var S_RADIO_INACTIVE = unicodeOr("○", " ");
|
|
789
|
+
var S_CHECKBOX_ACTIVE = unicodeOr("◻", "[•]");
|
|
790
|
+
var S_CHECKBOX_SELECTED = unicodeOr("◼", "[+]");
|
|
791
|
+
var S_CHECKBOX_INACTIVE = unicodeOr("◻", "[ ]");
|
|
792
|
+
var S_PASSWORD_MASK = unicodeOr("▪", "•");
|
|
793
|
+
var S_BAR_H = unicodeOr("─", "-");
|
|
794
|
+
var S_CORNER_TOP_RIGHT = unicodeOr("╮", "+");
|
|
795
|
+
var S_CONNECT_LEFT = unicodeOr("├", "+");
|
|
796
|
+
var S_CORNER_BOTTOM_RIGHT = unicodeOr("╯", "+");
|
|
797
|
+
var S_CORNER_BOTTOM_LEFT = unicodeOr("╰", "+");
|
|
798
|
+
var S_CORNER_TOP_LEFT = unicodeOr("╭", "+");
|
|
799
|
+
var S_INFO = unicodeOr("●", "•");
|
|
800
|
+
var S_SUCCESS = unicodeOr("◆", "*");
|
|
801
|
+
var S_WARN = unicodeOr("▲", "!");
|
|
802
|
+
var S_ERROR = unicodeOr("■", "x");
|
|
803
|
+
var symbol = (o) => {
|
|
804
|
+
switch (o) {
|
|
805
|
+
case "initial":
|
|
806
|
+
case "active":
|
|
807
|
+
return styleText("cyan", S_STEP_ACTIVE);
|
|
808
|
+
case "cancel":
|
|
809
|
+
return styleText("red", S_STEP_CANCEL);
|
|
810
|
+
case "error":
|
|
811
|
+
return styleText("yellow", S_STEP_ERROR);
|
|
812
|
+
case "submit":
|
|
813
|
+
return styleText("green", S_STEP_SUBMIT);
|
|
814
|
+
}
|
|
815
|
+
};
|
|
816
|
+
var symbolBar = (o) => {
|
|
817
|
+
switch (o) {
|
|
818
|
+
case "initial":
|
|
819
|
+
case "active":
|
|
820
|
+
return styleText("cyan", S_BAR);
|
|
821
|
+
case "cancel":
|
|
822
|
+
return styleText("red", S_BAR);
|
|
823
|
+
case "error":
|
|
824
|
+
return styleText("yellow", S_BAR);
|
|
825
|
+
case "submit":
|
|
826
|
+
return styleText("green", S_BAR);
|
|
827
|
+
}
|
|
828
|
+
};
|
|
829
|
+
function formatInstructionFooter(o, e) {
|
|
830
|
+
const r2 = [`${e ? `${styleText("cyan", S_BAR)} ` : ""}${o.join(" • ")}`];
|
|
831
|
+
return e && r2.push(styleText("cyan", S_BAR_END)), r2;
|
|
832
|
+
}
|
|
833
|
+
var I = (l2, e, w, p, b, C = false) => {
|
|
834
|
+
let r2 = e, O = 0;
|
|
835
|
+
if (C)
|
|
836
|
+
for (let i = p - 1;i >= w; i--) {
|
|
837
|
+
const m = l2[i];
|
|
838
|
+
if (m && (r2 -= m.length), O++, r2 <= b)
|
|
839
|
+
break;
|
|
840
|
+
}
|
|
841
|
+
else
|
|
842
|
+
for (let i = w;i < p; i++) {
|
|
843
|
+
const m = l2[i];
|
|
844
|
+
if (m && (r2 -= m.length), O++, r2 <= b)
|
|
845
|
+
break;
|
|
846
|
+
}
|
|
847
|
+
return { lineCount: r2, removals: O };
|
|
848
|
+
};
|
|
849
|
+
var limitOptions = ({
|
|
850
|
+
cursor: l2,
|
|
851
|
+
options: e,
|
|
852
|
+
style: w,
|
|
853
|
+
output: p = process.stdout,
|
|
854
|
+
maxItems: b = Number.POSITIVE_INFINITY,
|
|
855
|
+
columnPadding: C = 0,
|
|
856
|
+
rowPadding: r2 = 4
|
|
857
|
+
}) => {
|
|
858
|
+
const i = getColumns(p) - C, m = getRows(p), M = styleText("dim", "..."), v = Math.max(m - r2, 0), a2 = Math.max(Math.min(b, v), 5);
|
|
859
|
+
let f = 0;
|
|
860
|
+
l2 >= a2 - 3 && (f = Math.max(Math.min(l2 - a2 + 3, e.length - a2), 0));
|
|
861
|
+
let d = a2 < e.length && f > 0, c = a2 < e.length && f + a2 < e.length;
|
|
862
|
+
const W = Math.min(f + a2, e.length), s = [];
|
|
863
|
+
let g = 0;
|
|
864
|
+
d && g++, c && g++;
|
|
865
|
+
const T = f + (d ? 1 : 0), y = W - (c ? 1 : 0);
|
|
866
|
+
for (let t2 = T;t2 < y; t2++) {
|
|
867
|
+
const n2 = e[t2], o = n2 ? w(n2, t2 === l2) : "", h2 = wrapAnsi(o, i, {
|
|
868
|
+
hard: true,
|
|
869
|
+
trim: false
|
|
870
|
+
}).split(`
|
|
871
|
+
`);
|
|
872
|
+
s.push(h2), g += h2.length;
|
|
873
|
+
}
|
|
874
|
+
if (g > v) {
|
|
875
|
+
let t2 = 0, n2 = 0, o = g;
|
|
876
|
+
const h2 = l2 - T;
|
|
877
|
+
let u2 = v;
|
|
878
|
+
const L = () => I(s, o, 0, h2, u2), E = () => I(s, o, h2 + 1, s.length, u2, true);
|
|
879
|
+
d ? ({ lineCount: o, removals: t2 } = L(), o > u2 && (c || (u2 -= 1), { lineCount: o, removals: n2 } = E())) : (c || (u2 -= 1), { lineCount: o, removals: n2 } = E(), o > u2 && (u2 -= 1, { lineCount: o, removals: t2 } = L())), t2 > 0 && (d = true, s.splice(0, t2)), n2 > 0 && (c = true, s.splice(s.length - n2, n2));
|
|
880
|
+
}
|
|
881
|
+
const x = [];
|
|
882
|
+
d && x.push(M);
|
|
883
|
+
for (const t2 of s)
|
|
884
|
+
for (const n2 of t2)
|
|
885
|
+
x.push(n2);
|
|
886
|
+
return c && x.push(M), x;
|
|
887
|
+
};
|
|
888
|
+
var MULTISELECT_INSTRUCTIONS = [
|
|
889
|
+
`${styleText("dim", "↑/↓")} to navigate`,
|
|
890
|
+
`${styleText("dim", "Space:")} select`,
|
|
891
|
+
`${styleText("dim", "Enter:")} confirm`
|
|
892
|
+
];
|
|
893
|
+
var m = (i, u2) => i.split(`
|
|
894
|
+
`).map((d) => u2(d)).join(`
|
|
895
|
+
`);
|
|
896
|
+
var multiselect = (i) => {
|
|
897
|
+
const u2 = (t2, a2) => {
|
|
898
|
+
const r2 = t2.label ?? String(t2.value);
|
|
899
|
+
return a2 === "disabled" ? `${styleText("gray", S_CHECKBOX_INACTIVE)} ${m(r2, (o) => styleText(["strikethrough", "gray"], o))}${t2.hint ? ` ${styleText("dim", `(${t2.hint ?? "disabled"})`)}` : ""}` : a2 === "active" ? `${styleText("cyan", S_CHECKBOX_ACTIVE)} ${r2}${t2.hint ? ` ${styleText("dim", `(${t2.hint})`)}` : ""}` : a2 === "selected" ? `${styleText("green", S_CHECKBOX_SELECTED)} ${m(r2, (o) => styleText("dim", o))}${t2.hint ? ` ${styleText("dim", `(${t2.hint})`)}` : ""}` : a2 === "cancelled" ? `${m(r2, (o) => styleText(["strikethrough", "dim"], o))}` : a2 === "active-selected" ? `${styleText("green", S_CHECKBOX_SELECTED)} ${r2}${t2.hint ? ` ${styleText("dim", `(${t2.hint})`)}` : ""}` : a2 === "submitted" ? `${m(r2, (o) => styleText("dim", o))}` : `${styleText("dim", S_CHECKBOX_INACTIVE)} ${m(r2, (o) => styleText("dim", o))}`;
|
|
900
|
+
}, d = i.required ?? true, v = i.showInstructions ?? true;
|
|
901
|
+
return new a({
|
|
902
|
+
options: i.options,
|
|
903
|
+
signal: i.signal,
|
|
904
|
+
input: i.input,
|
|
905
|
+
output: i.output,
|
|
906
|
+
initialValues: i.initialValues,
|
|
907
|
+
required: d,
|
|
908
|
+
cursorAt: i.cursorAt,
|
|
909
|
+
validate(t2) {
|
|
910
|
+
if (d && (t2 === undefined || t2.length === 0))
|
|
911
|
+
return `Please select at least one option.
|
|
912
|
+
${styleText("reset", styleText("dim", `Press ${styleText(["gray", "bgWhite", "inverse"], " space ")} to select, ${styleText("gray", styleText("bgWhite", styleText("inverse", " enter ")))} to submit`))}`;
|
|
913
|
+
},
|
|
914
|
+
render() {
|
|
915
|
+
const t2 = i.withGuide ?? settings.withGuide, a2 = wrapTextWithPrefix(i.output, i.message, t2 ? `${symbolBar(this.state)} ` : "", `${symbol(this.state)} `), r2 = `${t2 ? `${styleText("gray", S_BAR)}
|
|
916
|
+
` : ""}${a2}
|
|
917
|
+
`, o = this.value ?? [], p = (n2, l2) => {
|
|
918
|
+
if (n2.disabled)
|
|
919
|
+
return u2(n2, "disabled");
|
|
920
|
+
const s = o.includes(n2.value);
|
|
921
|
+
return l2 && s ? u2(n2, "active-selected") : s ? u2(n2, "selected") : u2(n2, l2 ? "active" : "inactive");
|
|
922
|
+
};
|
|
923
|
+
switch (this.state) {
|
|
924
|
+
case "submit": {
|
|
925
|
+
const n2 = this.options.filter(({ value: s }) => o.includes(s)).map((s) => u2(s, "submitted")).join(styleText("dim", ", ")) || styleText("dim", "none"), l2 = wrapTextWithPrefix(i.output, n2, t2 ? `${styleText("gray", S_BAR)} ` : "");
|
|
926
|
+
return `${r2}${l2}`;
|
|
927
|
+
}
|
|
928
|
+
case "cancel": {
|
|
929
|
+
const n2 = this.options.filter(({ value: s }) => o.includes(s)).map((s) => u2(s, "cancelled")).join(styleText("dim", ", "));
|
|
930
|
+
if (n2.trim() === "")
|
|
931
|
+
return `${r2}${styleText("gray", S_BAR)}`;
|
|
932
|
+
const l2 = wrapTextWithPrefix(i.output, n2, t2 ? `${styleText("gray", S_BAR)} ` : "");
|
|
933
|
+
return `${r2}${l2}${t2 ? `
|
|
934
|
+
${styleText("gray", S_BAR)}` : ""}`;
|
|
935
|
+
}
|
|
936
|
+
case "error": {
|
|
937
|
+
const n2 = t2 ? `${styleText("yellow", S_BAR)} ` : "", l2 = this.error.split(`
|
|
938
|
+
`).map(($, C) => C === 0 ? `${t2 ? `${styleText("yellow", S_BAR_END)} ` : ""}${styleText("yellow", $)}` : ` ${$}`).join(`
|
|
939
|
+
`), s = r2.split(`
|
|
940
|
+
`).length, h2 = l2.split(`
|
|
941
|
+
`).length + 1;
|
|
942
|
+
return `${r2}${n2}${limitOptions({
|
|
943
|
+
output: i.output,
|
|
944
|
+
options: this.options,
|
|
945
|
+
cursor: this.cursor,
|
|
946
|
+
maxItems: i.maxItems,
|
|
947
|
+
columnPadding: n2.length,
|
|
948
|
+
rowPadding: s + h2,
|
|
949
|
+
style: p
|
|
950
|
+
}).join(`
|
|
951
|
+
${n2}`)}
|
|
952
|
+
${l2}
|
|
953
|
+
`;
|
|
954
|
+
}
|
|
955
|
+
default: {
|
|
956
|
+
const n2 = t2 ? `${styleText("cyan", S_BAR)} ` : "", l2 = r2.split(`
|
|
957
|
+
`).length, s = v ? formatInstructionFooter(MULTISELECT_INSTRUCTIONS, t2) : t2 ? [styleText("cyan", S_BAR_END)] : [], h2 = s.join(`
|
|
958
|
+
`), $ = s.length + 1;
|
|
959
|
+
return `${r2}${n2}${limitOptions({
|
|
960
|
+
output: i.output,
|
|
961
|
+
options: this.options,
|
|
962
|
+
cursor: this.cursor,
|
|
963
|
+
maxItems: i.maxItems,
|
|
964
|
+
columnPadding: n2.length,
|
|
965
|
+
rowPadding: l2 + $,
|
|
966
|
+
style: p
|
|
967
|
+
}).join(`
|
|
968
|
+
${n2}`)}
|
|
969
|
+
${h2}
|
|
970
|
+
`;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
}).prompt();
|
|
975
|
+
};
|
|
976
|
+
var log = {
|
|
977
|
+
message: (s = [], {
|
|
978
|
+
symbol: e = styleText("gray", S_BAR),
|
|
979
|
+
secondarySymbol: r2 = styleText("gray", S_BAR),
|
|
980
|
+
output: m2 = process.stdout,
|
|
981
|
+
spacing: l2 = 1,
|
|
982
|
+
withGuide: c
|
|
983
|
+
} = {}) => {
|
|
984
|
+
const t2 = [], o = c ?? settings.withGuide, f = o ? r2 : "", O = o ? `${e} ` : "", u2 = o ? `${r2} ` : "";
|
|
985
|
+
for (let i = 0;i < l2; i++)
|
|
986
|
+
t2.push(f);
|
|
987
|
+
const g = Array.isArray(s) ? s : s.split(`
|
|
988
|
+
`);
|
|
989
|
+
if (g.length > 0) {
|
|
990
|
+
const [i, ...y] = g;
|
|
991
|
+
i.length > 0 ? t2.push(`${O}${i}`) : t2.push(o ? e : "");
|
|
992
|
+
for (const p of y)
|
|
993
|
+
p.length > 0 ? t2.push(`${u2}${p}`) : t2.push(o ? r2 : "");
|
|
994
|
+
}
|
|
995
|
+
m2.write(`${t2.join(`
|
|
996
|
+
`)}
|
|
997
|
+
`);
|
|
998
|
+
},
|
|
999
|
+
info: (s, e) => {
|
|
1000
|
+
log.message(s, { ...e, symbol: styleText("blue", S_INFO) });
|
|
1001
|
+
},
|
|
1002
|
+
success: (s, e) => {
|
|
1003
|
+
log.message(s, { ...e, symbol: styleText("green", S_SUCCESS) });
|
|
1004
|
+
},
|
|
1005
|
+
step: (s, e) => {
|
|
1006
|
+
log.message(s, { ...e, symbol: styleText("green", S_STEP_SUBMIT) });
|
|
1007
|
+
},
|
|
1008
|
+
warn: (s, e) => {
|
|
1009
|
+
log.message(s, { ...e, symbol: styleText("yellow", S_WARN) });
|
|
1010
|
+
},
|
|
1011
|
+
warning: (s, e) => {
|
|
1012
|
+
log.warn(s, e);
|
|
1013
|
+
},
|
|
1014
|
+
error: (s, e) => {
|
|
1015
|
+
log.message(s, { ...e, symbol: styleText("red", S_ERROR) });
|
|
1016
|
+
}
|
|
1017
|
+
};
|
|
1018
|
+
var W = (l2) => styleText("magenta", l2);
|
|
1019
|
+
var spinner = ({
|
|
1020
|
+
indicator: l2 = "dots",
|
|
1021
|
+
onCancel: h2,
|
|
1022
|
+
output: n2 = process.stdout,
|
|
1023
|
+
cancelMessage: G,
|
|
1024
|
+
errorMessage: O,
|
|
1025
|
+
frames: E = unicode ? ["◒", "◐", "◓", "◑"] : ["•", "o", "O", "0"],
|
|
1026
|
+
delay: F = unicode ? 80 : 120,
|
|
1027
|
+
signal: m2,
|
|
1028
|
+
...I2
|
|
1029
|
+
} = {}) => {
|
|
1030
|
+
const u2 = isCI();
|
|
1031
|
+
let M, T, d = false, S = false, s = "", p, w = performance.now();
|
|
1032
|
+
const x = getColumns(n2), k = I2?.styleFrame ?? W, g = (e) => {
|
|
1033
|
+
const r2 = e > 1 ? O ?? settings.messages.error : G ?? settings.messages.cancel;
|
|
1034
|
+
S = e === 1, d && (a2(r2, e), S && typeof h2 == "function" && h2());
|
|
1035
|
+
}, f = () => g(2), i = () => g(1), A = () => {
|
|
1036
|
+
process.on("uncaughtExceptionMonitor", f), process.on("unhandledRejection", f), process.on("SIGINT", i), process.on("SIGTERM", i), process.on("exit", g), m2 && m2.addEventListener("abort", i);
|
|
1037
|
+
}, H = () => {
|
|
1038
|
+
process.removeListener("uncaughtExceptionMonitor", f), process.removeListener("unhandledRejection", f), process.removeListener("SIGINT", i), process.removeListener("SIGTERM", i), process.removeListener("exit", g), m2 && m2.removeEventListener("abort", i);
|
|
1039
|
+
}, y = () => {
|
|
1040
|
+
if (p === undefined)
|
|
1041
|
+
return;
|
|
1042
|
+
u2 && n2.write(`
|
|
1043
|
+
`);
|
|
1044
|
+
const r2 = wrapAnsi(p, x, {
|
|
1045
|
+
hard: true,
|
|
1046
|
+
trim: false
|
|
1047
|
+
}).split(`
|
|
1048
|
+
`);
|
|
1049
|
+
r2.length > 1 && n2.write(import_sisteransi2.cursor.up(r2.length - 1)), n2.write(import_sisteransi2.cursor.to(0)), n2.write(import_sisteransi2.erase.down());
|
|
1050
|
+
}, C = (e) => e.replace(/\.+$/, ""), _ = (e) => {
|
|
1051
|
+
const r2 = (performance.now() - e) / 1000, t2 = Math.floor(r2 / 60), o = Math.floor(r2 % 60);
|
|
1052
|
+
return t2 > 0 ? `[${t2}m ${o}s]` : `[${o}s]`;
|
|
1053
|
+
}, N = I2.withGuide ?? settings.withGuide, P = (e = "") => {
|
|
1054
|
+
d = true, M = block({ output: n2 }), s = C(e), w = performance.now(), N && n2.write(`${styleText("gray", S_BAR)}
|
|
1055
|
+
`);
|
|
1056
|
+
let r2 = 0, t2 = 0;
|
|
1057
|
+
A(), T = setInterval(() => {
|
|
1058
|
+
if (u2 && s === p)
|
|
1059
|
+
return;
|
|
1060
|
+
y(), p = s;
|
|
1061
|
+
const o = k(E[r2]);
|
|
1062
|
+
let v;
|
|
1063
|
+
if (u2)
|
|
1064
|
+
v = `${o} ${s}...`;
|
|
1065
|
+
else if (l2 === "timer")
|
|
1066
|
+
v = `${o} ${s} ${_(w)}`;
|
|
1067
|
+
else {
|
|
1068
|
+
const B = ".".repeat(Math.floor(t2)).slice(0, 3);
|
|
1069
|
+
v = `${o} ${s}${B}`;
|
|
1070
|
+
}
|
|
1071
|
+
const j = wrapAnsi(v, x, {
|
|
1072
|
+
hard: true,
|
|
1073
|
+
trim: false
|
|
1074
|
+
});
|
|
1075
|
+
n2.write(j), r2 = r2 + 1 < E.length ? r2 + 1 : 0, t2 = t2 < 4 ? t2 + 0.125 : 0;
|
|
1076
|
+
}, F);
|
|
1077
|
+
}, a2 = (e = "", r2 = 0, t2 = false) => {
|
|
1078
|
+
if (!d)
|
|
1079
|
+
return;
|
|
1080
|
+
d = false, clearInterval(T), y();
|
|
1081
|
+
const o = r2 === 0 ? styleText("green", S_STEP_SUBMIT) : r2 === 1 ? styleText("red", S_STEP_CANCEL) : styleText("red", S_STEP_ERROR);
|
|
1082
|
+
s = e ?? s, t2 || (l2 === "timer" ? n2.write(`${o} ${s} ${_(w)}
|
|
1083
|
+
`) : n2.write(`${o} ${s}
|
|
1084
|
+
`)), H(), M();
|
|
1085
|
+
};
|
|
1086
|
+
return {
|
|
1087
|
+
start: P,
|
|
1088
|
+
stop: (e = "") => a2(e, 0),
|
|
1089
|
+
message: (e = "") => {
|
|
1090
|
+
s = C(e ?? s);
|
|
1091
|
+
},
|
|
1092
|
+
cancel: (e = "") => a2(e, 1),
|
|
1093
|
+
error: (e = "") => a2(e, 2),
|
|
1094
|
+
clear: () => a2("", 0, true),
|
|
1095
|
+
get isCancelled() {
|
|
1096
|
+
return S;
|
|
1097
|
+
}
|
|
1098
|
+
};
|
|
1099
|
+
};
|
|
1100
|
+
var u2 = {
|
|
1101
|
+
light: unicodeOr("─", "-"),
|
|
1102
|
+
heavy: unicodeOr("━", "="),
|
|
1103
|
+
block: unicodeOr("█", "#")
|
|
1104
|
+
};
|
|
1105
|
+
var SELECT_INSTRUCTIONS = [
|
|
1106
|
+
`${styleText("dim", "↑/↓")} to navigate`,
|
|
1107
|
+
`${styleText("dim", "Enter:")} confirm`
|
|
1108
|
+
];
|
|
1109
|
+
var i = `${styleText("gray", S_BAR)} `;
|
|
2
1110
|
|
|
3
1111
|
// src/cli.ts
|
|
4
1112
|
import { randomBytes } from "node:crypto";
|
|
@@ -16,9 +1124,9 @@ import {
|
|
|
16
1124
|
} from "node:fs/promises";
|
|
17
1125
|
import { homedir } from "node:os";
|
|
18
1126
|
import { dirname, extname, join, resolve } from "node:path";
|
|
19
|
-
import {
|
|
1127
|
+
import { styleText as styleText2 } from "node:util";
|
|
20
1128
|
import { fileURLToPath } from "node:url";
|
|
21
|
-
var packageVersion = "0.
|
|
1129
|
+
var packageVersion = "0.3.1";
|
|
22
1130
|
var configDirectory = join(process.env.XDG_CONFIG_HOME ?? join(homedir(), ".config"), "gh-postplan");
|
|
23
1131
|
var cacheDirectory = join(process.env.XDG_CACHE_HOME ?? join(homedir(), ".cache"), "gh-postplan");
|
|
24
1132
|
var configPath = join(configDirectory, "config.json");
|
|
@@ -88,14 +1196,9 @@ function pageUrls(base, id, version) {
|
|
|
88
1196
|
const root = `${base.replace(/\/+$/, "")}/drafts/${id}/`;
|
|
89
1197
|
return { current: root, version: `${root}v${version}/` };
|
|
90
1198
|
}
|
|
91
|
-
function
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const choices = answer.split(",").map((choice) => Number(choice.trim()));
|
|
95
|
-
if (choices.some((choice) => !Number.isInteger(choice) || choice < 1 || choice > count)) {
|
|
96
|
-
throw new Error(`Choose numbers from 1 to ${count}, separated by commas`);
|
|
97
|
-
}
|
|
98
|
-
return [...new Set(choices)];
|
|
1199
|
+
function htmlTitle(html) {
|
|
1200
|
+
const title = /<title\b[^>]*>([\s\S]*?)<\/title>/i.exec(html)?.[1] ?? "Untitled draft";
|
|
1201
|
+
return title.replace(/&#(\d+);|&#x([\da-f]+);|&(amp|lt|gt|quot|apos);/gi, (_, decimal, hex, named) => decimal ? String.fromCodePoint(Number(decimal)) : hex ? String.fromCodePoint(Number.parseInt(hex, 16)) : { amp: "&", lt: "<", gt: ">", quot: '"', apos: "'" }[named.toLowerCase()] ?? "").replace(/[\u0000-\u001f\u007f]+/g, " ").replace(/\s+/g, " ").trim() || "Untitled draft";
|
|
99
1202
|
}
|
|
100
1203
|
function validateRepo(repo) {
|
|
101
1204
|
if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(repo)) {
|
|
@@ -105,13 +1208,13 @@ function validateRepo(repo) {
|
|
|
105
1208
|
async function run(command, args, cwd) {
|
|
106
1209
|
return new Promise((resolveRun, reject) => {
|
|
107
1210
|
const child = spawn(command, args, { cwd, stdio: ["ignore", "pipe", "pipe"] });
|
|
108
|
-
const
|
|
1211
|
+
const stdout2 = [];
|
|
109
1212
|
const stderr = [];
|
|
110
|
-
child.stdout.on("data", (chunk) =>
|
|
1213
|
+
child.stdout.on("data", (chunk) => stdout2.push(chunk));
|
|
111
1214
|
child.stderr.on("data", (chunk) => stderr.push(chunk));
|
|
112
1215
|
child.on("error", reject);
|
|
113
1216
|
child.on("close", (code) => {
|
|
114
|
-
const output = Buffer.concat(
|
|
1217
|
+
const output = Buffer.concat(stdout2).toString().trim();
|
|
115
1218
|
const error = Buffer.concat(stderr).toString().trim();
|
|
116
1219
|
if (code === 0)
|
|
117
1220
|
resolveRun(output);
|
|
@@ -236,7 +1339,7 @@ async function setup({ repo, create }) {
|
|
|
236
1339
|
await run("git", ["push", ...hadRemoteBranch ? [] : ["-u"], "origin", "gh-pages"], path);
|
|
237
1340
|
}
|
|
238
1341
|
const pages = await configurePages(repo);
|
|
239
|
-
await writeJson(configPath, { repo });
|
|
1342
|
+
await writeJson(configPath, { repo, pagesUrl: pages.html_url });
|
|
240
1343
|
process.stderr.write(`Configured ${repo}
|
|
241
1344
|
${pages.html_url}
|
|
242
1345
|
`);
|
|
@@ -270,11 +1373,21 @@ async function getRepo() {
|
|
|
270
1373
|
validateRepo(repo);
|
|
271
1374
|
return repo;
|
|
272
1375
|
}
|
|
1376
|
+
async function cachedPagesUrl(repo, path) {
|
|
1377
|
+
const config = await readJson(configPath, {});
|
|
1378
|
+
if (config.repo === repo && config.pagesUrl)
|
|
1379
|
+
return config.pagesUrl;
|
|
1380
|
+
const customDomain = await readFile(join(path, "CNAME"), "utf8").catch(() => "");
|
|
1381
|
+
if (customDomain.trim())
|
|
1382
|
+
return `https://${customDomain.trim()}/`;
|
|
1383
|
+
const [owner, name] = repo.split("/");
|
|
1384
|
+
return name.toLowerCase() === `${owner.toLowerCase()}.github.io` ? `https://${owner}.github.io/` : `https://${owner}.github.io/${name}/`;
|
|
1385
|
+
}
|
|
273
1386
|
async function readPublishedDrafts(repo) {
|
|
274
|
-
const path =
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
const
|
|
1387
|
+
const path = clonePath(repo);
|
|
1388
|
+
if (!await exists(join(path, ".git")))
|
|
1389
|
+
throw new Error("No cached drafts. Publish one first.");
|
|
1390
|
+
const pagesUrl = await cachedPagesUrl(repo, path);
|
|
278
1391
|
const directory = join(path, "drafts");
|
|
279
1392
|
if (!await exists(directory))
|
|
280
1393
|
return [];
|
|
@@ -284,19 +1397,36 @@ async function readPublishedDrafts(repo) {
|
|
|
284
1397
|
if (!(await stat(draftDirectory)).isDirectory() || !await exists(join(draftDirectory, "index.html")))
|
|
285
1398
|
continue;
|
|
286
1399
|
const versions = (await readdir(draftDirectory)).filter((entry) => /^v\d+$/.test(entry)).length;
|
|
287
|
-
|
|
1400
|
+
const title = htmlTitle(await readFile(join(draftDirectory, "index.html"), "utf8"));
|
|
1401
|
+
drafts.push({ id, versions, title, url: pageUrls(pagesUrl, id, 1).current });
|
|
288
1402
|
}
|
|
289
|
-
return drafts.sort((
|
|
1403
|
+
return drafts.sort((a2, b) => a2.title.localeCompare(b.title));
|
|
290
1404
|
}
|
|
291
1405
|
async function list() {
|
|
292
1406
|
const repo = await getRepo();
|
|
293
|
-
await checkTools();
|
|
294
1407
|
const drafts = await readPublishedDrafts(repo);
|
|
295
1408
|
if (drafts.length === 0)
|
|
296
1409
|
return void process.stdout.write(`No drafts published.
|
|
1410
|
+
`);
|
|
1411
|
+
const color = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
1412
|
+
const paint = (format, text) => color ? styleText2(format, text) : text;
|
|
1413
|
+
const titleWidth = Math.min(40, Math.max("TITLE".length, ...drafts.map((draft) => draft.title.length)));
|
|
1414
|
+
const fitTitle = (title) => title.length > titleWidth ? `${title.slice(0, titleWidth - 1)}…` : title;
|
|
1415
|
+
const showUrls = (process.stdout.columns ?? 80) >= titleWidth + 31 + Math.max(...drafts.map((draft) => draft.url.length));
|
|
1416
|
+
const columns = (title, versions, id, url) => `${title.padEnd(titleWidth)} ${versions.padEnd(8)} ${id.padEnd(12)}${showUrls ? ` ${url}` : ""}`;
|
|
1417
|
+
process.stdout.write(`${paint("bold", `Drafts (${drafts.length})`)}
|
|
1418
|
+
|
|
1419
|
+
`);
|
|
1420
|
+
process.stdout.write(`${paint("bold", columns("TITLE", "VERSIONS", "DRAFT ID", "URL"))}
|
|
1421
|
+
`);
|
|
1422
|
+
process.stdout.write(`${paint("dim", columns("─".repeat(titleWidth), "────────", "────────────", "─".repeat(24)))}
|
|
297
1423
|
`);
|
|
298
1424
|
for (const draft of drafts) {
|
|
299
|
-
|
|
1425
|
+
const row = columns(fitTitle(draft.title), String(draft.versions), draft.id, draft.url);
|
|
1426
|
+
process.stdout.write(`${paint("cyan", row)}
|
|
1427
|
+
`);
|
|
1428
|
+
if (!showUrls)
|
|
1429
|
+
process.stdout.write(`${paint("blue", ` ${draft.url}`)}
|
|
300
1430
|
`);
|
|
301
1431
|
}
|
|
302
1432
|
}
|
|
@@ -304,23 +1434,28 @@ async function deleteDrafts() {
|
|
|
304
1434
|
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
305
1435
|
throw new Error("delete requires an interactive terminal");
|
|
306
1436
|
const repo = await getRepo();
|
|
307
|
-
await checkTools();
|
|
308
1437
|
const drafts = await readPublishedDrafts(repo);
|
|
309
1438
|
if (drafts.length === 0)
|
|
310
1439
|
return void process.stdout.write(`No drafts published.
|
|
311
1440
|
`);
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
1441
|
+
const selected = await multiselect({
|
|
1442
|
+
message: "Select drafts to delete",
|
|
1443
|
+
options: drafts.map((draft) => ({
|
|
1444
|
+
label: draft.title,
|
|
1445
|
+
value: draft,
|
|
1446
|
+
hint: `${draft.id} · ${draft.versions} version${draft.versions === 1 ? "" : "s"}`
|
|
1447
|
+
})),
|
|
1448
|
+
maxItems: 12,
|
|
1449
|
+
required: false
|
|
315
1450
|
});
|
|
316
|
-
|
|
317
|
-
const answer = await prompt.question("Delete which drafts? Enter numbers separated by commas, or press Enter to cancel: ");
|
|
318
|
-
prompt.close();
|
|
319
|
-
const selected = parseSelection(answer, drafts.length).map((choice) => drafts[choice - 1]);
|
|
320
|
-
if (selected.length === 0)
|
|
1451
|
+
if (isCancel(selected) || selected.length === 0)
|
|
321
1452
|
return void process.stdout.write(`Cancelled.
|
|
322
1453
|
`);
|
|
323
1454
|
const path = clonePath(repo);
|
|
1455
|
+
const status = await run("git", ["status", "--porcelain"], path);
|
|
1456
|
+
if (status)
|
|
1457
|
+
throw new Error("Cached drafts contain unfinished changes; publish again before deleting");
|
|
1458
|
+
await run("git", ["pull", "--ff-only", "origin", "gh-pages"], path);
|
|
324
1459
|
for (const draft of selected)
|
|
325
1460
|
await rm(join(path, "drafts", draft.id), { recursive: true });
|
|
326
1461
|
await run("git", ["add", "-A", ...selected.map((draft) => join("drafts", draft.id))], path);
|
|
@@ -339,14 +1474,16 @@ async function makeDraftId(path) {
|
|
|
339
1474
|
while (await exists(join(path, "drafts", id)));
|
|
340
1475
|
return id;
|
|
341
1476
|
}
|
|
342
|
-
async function verifyPublished(url, expected) {
|
|
1477
|
+
async function verifyPublished(url, expected, signal) {
|
|
343
1478
|
const deadline = Date.now() + 120000;
|
|
344
|
-
while (Date.now() < deadline) {
|
|
1479
|
+
while (Date.now() < deadline && !signal.aborted) {
|
|
345
1480
|
try {
|
|
346
|
-
const response = await fetch(url, { cache: "no-store" });
|
|
1481
|
+
const response = await fetch(url, { cache: "no-store", signal });
|
|
347
1482
|
if (response.ok && Buffer.from(await response.arrayBuffer()).equals(expected))
|
|
348
1483
|
return true;
|
|
349
1484
|
} catch {}
|
|
1485
|
+
if (signal.aborted)
|
|
1486
|
+
return false;
|
|
350
1487
|
await new Promise((resolveWait) => setTimeout(resolveWait, 2000));
|
|
351
1488
|
}
|
|
352
1489
|
return false;
|
|
@@ -414,11 +1551,26 @@ async function publish(command) {
|
|
|
414
1551
|
process.stderr.write(`Permanent version: ${urls.version}
|
|
415
1552
|
`);
|
|
416
1553
|
if (command.wait) {
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
1554
|
+
const abort = new AbortController;
|
|
1555
|
+
const deployment = spinner({
|
|
1556
|
+
indicator: "timer",
|
|
1557
|
+
onCancel: () => abort.abort(),
|
|
1558
|
+
output: process.stderr,
|
|
1559
|
+
withGuide: false
|
|
1560
|
+
});
|
|
1561
|
+
deployment.start("Waiting for GitHub Pages");
|
|
1562
|
+
if (await verifyPublished(urls.version, content, abort.signal))
|
|
1563
|
+
deployment.stop("GitHub Pages is ready");
|
|
1564
|
+
else if (deployment.isCancelled) {
|
|
1565
|
+
process.exitCode = 130;
|
|
1566
|
+
return;
|
|
1567
|
+
} else {
|
|
1568
|
+
deployment.clear();
|
|
1569
|
+
log.warn(`GitHub Pages is still deploying ${urls.version}`, {
|
|
1570
|
+
output: process.stderr,
|
|
1571
|
+
spacing: 0,
|
|
1572
|
+
withGuide: false
|
|
1573
|
+
});
|
|
422
1574
|
}
|
|
423
1575
|
}
|
|
424
1576
|
process.stdout.write(`${urls.current}
|
|
@@ -450,9 +1602,9 @@ if (executablePath === fileURLToPath(import.meta.url)) {
|
|
|
450
1602
|
});
|
|
451
1603
|
}
|
|
452
1604
|
export {
|
|
1605
|
+
htmlTitle,
|
|
453
1606
|
main,
|
|
454
1607
|
nextVersion,
|
|
455
1608
|
pageUrls,
|
|
456
|
-
parseCommand
|
|
457
|
-
parseSelection
|
|
1609
|
+
parseCommand
|
|
458
1610
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gh-postplan",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Publish versioned HTML drafts to GitHub Pages",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -30,5 +30,8 @@
|
|
|
30
30
|
"@types/bun": "latest",
|
|
31
31
|
"@types/node": "latest",
|
|
32
32
|
"typescript": "latest"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@clack/prompts": "^1.7.0"
|
|
33
36
|
}
|
|
34
37
|
}
|
|
@@ -75,4 +75,4 @@ npx gh-postplan list
|
|
|
75
75
|
npx gh-postplan delete
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
Deleting a draft also deletes all of its permanent versions.
|
|
78
|
+
The list is read from the local cache and shows each HTML title. In the delete prompt, use the arrow keys to move, Space to select drafts, and Enter to confirm. Deleting a draft also deletes all of its permanent versions.
|