@retasc/cli 1.16.0 → 1.16.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/CHANGELOG.md +23 -0
- package/dist/commands/import.js +64 -9
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,29 @@ release commits and the issues they reference.
|
|
|
6
6
|
|
|
7
7
|
Dates are the npm publish date. Each entry names the RTSC issue behind it.
|
|
8
8
|
|
|
9
|
+
## 1.16.1 (2026-08-02)
|
|
10
|
+
|
|
11
|
+
- **RTSC-528** — two things the first real `retasc import` run turned up.
|
|
12
|
+
|
|
13
|
+
**The progress bar never appeared.** It only started drawing once it had seen the run
|
|
14
|
+
reported as running, and a 15-issue import finishes before that is ever observed, so the
|
|
15
|
+
output went straight from `Importing…` to `✓ Imported.` with a silent gap. It now draws
|
|
16
|
+
the moment the run starts, sweeping while it waits for counts and switching to the real
|
|
17
|
+
bar once they arrive. Still silent without a terminal and under `NO_COLOR`.
|
|
18
|
+
|
|
19
|
+
**The column prompt didn't say what to do.** It read
|
|
20
|
+
`to do [todo] (todo / doing / done / canceled):`, where nothing is a verb, so the first
|
|
21
|
+
person to run it had to guess that you type one of the words. Now:
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
to do
|
|
25
|
+
Enter to keep todo, or type: doing, done, canceled
|
|
26
|
+
>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The suggestion is no longer repeated among the alternatives, which is what made the old
|
|
30
|
+
line read as four equal options behind a mysterious bracket.
|
|
31
|
+
|
|
9
32
|
## 1.16.0 (2026-08-02)
|
|
10
33
|
|
|
11
34
|
- **RTSC-526** — `retasc import` catches up with the Dash on four things.
|
package/dist/commands/import.js
CHANGED
|
@@ -72,6 +72,19 @@ export function summaryLines(summary, label) {
|
|
|
72
72
|
const LIME = "\x1b[38;5;154m";
|
|
73
73
|
const DIM = "\x1b[38;5;240m";
|
|
74
74
|
const RESET = "\x1b[0m";
|
|
75
|
+
/**
|
|
76
|
+
* An indeterminate sweep, for the stretch before the server reports counts (RTSC-528).
|
|
77
|
+
*
|
|
78
|
+
* Pure and frame-indexed rather than time-based, so a test can pin every frame. A block
|
|
79
|
+
* that travels is the honest shape when the total is unknown: a 0% bar reads as stalled,
|
|
80
|
+
* which is the very impression this is here to prevent.
|
|
81
|
+
*/
|
|
82
|
+
export function sweep(frame, width = 24, color = true) {
|
|
83
|
+
const pos = frame % (width * 2 - 2);
|
|
84
|
+
const at = pos < width ? pos : width * 2 - 2 - pos; // bounce, so it never jumps
|
|
85
|
+
const cells = Array.from({ length: width }, (_, i) => Math.abs(i - at) <= 1 ? "\u2588" : "\u2591").join("");
|
|
86
|
+
return ` ${color ? LIME : ""}${cells}${color ? RESET : ""} working…`;
|
|
87
|
+
}
|
|
75
88
|
/**
|
|
76
89
|
* One line of progress bar.
|
|
77
90
|
*
|
|
@@ -167,7 +180,8 @@ export async function mapStatuses(statuses, reviewers, askFn) {
|
|
|
167
180
|
const statusMap = {};
|
|
168
181
|
const reviewerByStatus = {};
|
|
169
182
|
console.log(`\nWhat does each column mean? ${statuses.length} to confirm.\n` +
|
|
170
|
-
" Enter
|
|
183
|
+
" Press Enter to keep the suggested answer, or type a different one.\n" +
|
|
184
|
+
" The suggestion comes from the column's type in your tool, not its name.");
|
|
171
185
|
// Grouped under the source's own section names, in the source's own order within each
|
|
172
186
|
// (RTSC-436/526). On a twenty-column Jira board a flat list is a wall; the sections are
|
|
173
187
|
// the shape the human already has in front of them in their tool.
|
|
@@ -183,7 +197,20 @@ export async function mapStatuses(statuses, reviewers, askFn) {
|
|
|
183
197
|
? s.suggested
|
|
184
198
|
: "todo";
|
|
185
199
|
for (let attempt = 0;; attempt++) {
|
|
186
|
-
|
|
200
|
+
// RTSC-528 — the prompt has to name the ACTION. It used to read
|
|
201
|
+
// `to do [todo] (todo / doing / done / canceled):`
|
|
202
|
+
// where nothing is a verb: the bracket is the default and the parenthesis is a bare
|
|
203
|
+
// word list, so the first person to run it had to guess that you type one of them.
|
|
204
|
+
// The reviewer picker two lines below says "Choose a number" and is unambiguous,
|
|
205
|
+
// which made the contrast worse.
|
|
206
|
+
//
|
|
207
|
+
// The suggestion is also removed from the alternatives — it is already what Enter
|
|
208
|
+
// does, and listing it again is what made the line read as four equal options with a
|
|
209
|
+
// mysterious bracket in front.
|
|
210
|
+
const others = allowed.filter((m) => m !== suggested);
|
|
211
|
+
const answer = (await askFn(`\n ${clean(s.name)}\n` +
|
|
212
|
+
` Enter to keep ${suggested}, or type: ${others.join(", ")}\n` +
|
|
213
|
+
` > `)).trim().toLowerCase();
|
|
187
214
|
const choice = answer === "" ? suggested : answer;
|
|
188
215
|
if (allowed.includes(choice)) {
|
|
189
216
|
statusMap[s.id] = choice;
|
|
@@ -224,28 +251,56 @@ export async function mapStatuses(statuses, reviewers, askFn) {
|
|
|
224
251
|
* import failure.
|
|
225
252
|
*/
|
|
226
253
|
function followProgress(orgId) {
|
|
227
|
-
const tty = Boolean(stdout.isTTY) && !process.env.NO_COLOR;
|
|
228
254
|
if (!stdout.isTTY)
|
|
229
255
|
return () => { };
|
|
256
|
+
const color = !process.env.NO_COLOR;
|
|
230
257
|
let stopped = false;
|
|
231
|
-
|
|
258
|
+
let frame = 0;
|
|
259
|
+
// Declared before the paint timer that reads it. Safe either way (the callback fires
|
|
260
|
+
// after this line runs), but reading a variable above its declaration is a trap to leave
|
|
261
|
+
// for the next person.
|
|
262
|
+
let latest = null;
|
|
263
|
+
// RTSC-528 — DRAW IMMEDIATELY, and keep drawing, rather than waiting to observe
|
|
264
|
+
// `status === "running"`.
|
|
265
|
+
//
|
|
266
|
+
// The first live run showed nothing at all: a 15-issue import is over in a couple of
|
|
267
|
+
// seconds, so the first poll landed before `runImport` had created the row and the second
|
|
268
|
+
// landed after it finished. `running` was never seen, so nothing was ever drawn — and the
|
|
269
|
+
// silent gap this exists to remove was exactly what the human got. A bar that only works
|
|
270
|
+
// on slow imports is a bar nobody sees while testing.
|
|
271
|
+
//
|
|
272
|
+
// So the render loop is independent of the data: it ticks on its own, showing an
|
|
273
|
+
// indeterminate sweep until counts arrive and the real bar once they do.
|
|
274
|
+
const draw = (done, total) => {
|
|
275
|
+
stdout.write(`\r\x1b[2K${done === null ? sweep(frame++, 24, color) : progressBar(done, total, 24, color)}`);
|
|
276
|
+
};
|
|
277
|
+
draw(null, null);
|
|
278
|
+
const paint = setInterval(() => {
|
|
279
|
+
if (!stopped && latest === null)
|
|
280
|
+
draw(null, null);
|
|
281
|
+
}, 120);
|
|
282
|
+
// Counts, whenever the server has them. Every failure is swallowed: this is decoration
|
|
283
|
+
// on a run happening regardless, and must never be what surfaces as an import failure.
|
|
284
|
+
const poll = async () => {
|
|
232
285
|
while (!stopped) {
|
|
233
286
|
try {
|
|
234
287
|
const p = (await api.latestImport({ orgId }));
|
|
235
288
|
if (!stopped && p && p.status === "running") {
|
|
236
|
-
|
|
289
|
+
latest = { done: p.issuesDone ?? 0, total: p.issuesTotal ?? null };
|
|
290
|
+
draw(latest.done, latest.total);
|
|
237
291
|
}
|
|
238
292
|
}
|
|
239
293
|
catch {
|
|
240
|
-
/* progress
|
|
294
|
+
/* progress never speaks for the run */
|
|
241
295
|
}
|
|
242
|
-
await new Promise((r) => setTimeout(r,
|
|
296
|
+
await new Promise((r) => setTimeout(r, 700));
|
|
243
297
|
}
|
|
244
298
|
};
|
|
245
|
-
void
|
|
299
|
+
void poll();
|
|
246
300
|
return () => {
|
|
247
301
|
stopped = true;
|
|
248
|
-
|
|
302
|
+
clearInterval(paint);
|
|
303
|
+
// Clear the line so the summary never lands on a half-drawn bar.
|
|
249
304
|
stdout.write("\r\x1b[2K");
|
|
250
305
|
};
|
|
251
306
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@retasc/cli",
|
|
3
|
-
"version": "1.16.
|
|
3
|
+
"version": "1.16.1",
|
|
4
4
|
"description": "Retasc CLI \u2014 the issue tracker AI agents pull work from. Sign in with GitHub or Google, create projects, mint agent API keys, and wire your agent to the Retasc MCP server in one command.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|