@retasc/cli 1.6.1 → 1.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,7 +8,7 @@ Issues live in a persistent, multi-tenant store; agents reach them through one M
8
8
  The `retasc` CLI signs you in, creates projects, mints agent API keys, and wires the MCP
9
9
  server into your agent in a single command.
10
10
 
11
- → [retasc.com](https://retasc.com)
11
+ → [retasc.com](https://retasc.com) · [Set up your agent](https://retasc.com/connect) · [Quickstart](https://docs.retasc.com/quickstart)
12
12
 
13
13
  ## Install
14
14
 
@@ -37,7 +37,9 @@ is stored in your home keystore (`~/.retasc/bindings.json`); the folder's `.mcp.
37
37
  **secret-free marker** (safe to commit). Each workspace is bound to exactly one org/project, so
38
38
  an agent can never file issues into the wrong one — the server enforces it by the key. From then
39
39
  on your agent calls `next_issue` / `next_batch` to atomically claim the top unblocked,
40
- prioritized work, and several agents run at once without ever claiming the same issue.
40
+ prioritized work, and several agents run at once without ever claiming the same issue — see
41
+ [Running Claude Code agents in parallel](https://retasc.com/guides/claude-code-parallel-agents)
42
+ for that workflow end to end.
41
43
 
42
44
  Run `retasc whoami` (shows this folder's binding) or `retasc doctor` (checks it) any time.
43
45
 
@@ -71,6 +73,9 @@ Run `retasc --help` or `retasc <command> --help` for the full set.
71
73
  ## Links
72
74
 
73
75
  - Website — [retasc.com](https://retasc.com)
76
+ - Set up your agent — [retasc.com/connect](https://retasc.com/connect)
77
+ - Docs + quickstart — [docs.retasc.com/quickstart](https://docs.retasc.com/quickstart)
78
+ - Parallel agents guide — [retasc.com/guides/claude-code-parallel-agents](https://retasc.com/guides/claude-code-parallel-agents)
74
79
  - Issues — [github.com/Retasc/retasc/issues](https://github.com/Retasc/retasc/issues)
75
80
 
76
81
  ## License
@@ -11,7 +11,13 @@ function isInteractive() {
11
11
  async function ask(question) {
12
12
  const rl = createInterface({ input: stdin, output: stdout });
13
13
  try {
14
- return (await rl.question(question)).trim();
14
+ // readline's question() NEVER settles when stdin hits EOF (Ctrl-D, or a
15
+ // closed pipe) — it silently drops the callback rather than resolving ""
16
+ // or throwing, so a bare `await` here wedges the CLI with no output and no
17
+ // exit. Race the close event so callers fail fast instead (RTSC-269).
18
+ const closed = new Promise((_, reject) => rl.once("close", () => reject(new Error("input closed"))));
19
+ closed.catch(() => { }); // the normal path closes rl too; that loser rejection is expected
20
+ return (await Promise.race([rl.question(question), closed])).trim();
15
21
  }
16
22
  finally {
17
23
  rl.close();
@@ -25,18 +31,37 @@ async function confirm(question, assumeYes) {
25
31
  const a = (await ask(`${question} [y/N] `)).toLowerCase();
26
32
  return a === "y" || a === "yes";
27
33
  }
28
- /** Pick from a list interactively, or return undefined to fall through to create. */
29
- async function pick(label, items, render) {
34
+ /**
35
+ * Pick from a list interactively. Returns the chosen item, or undefined when the
36
+ * user explicitly picks the trailing "create new" option.
37
+ *
38
+ * Invalid input re-prompts rather than falling through: undefined used to mean
39
+ * BOTH "chose create-new" and "typed garbage", so a typo like `1)` silently
40
+ * created a new org/project instead of selecting option 1 (RTSC-269).
41
+ *
42
+ * The answer must be plain digits. Number() alone accepts "0x4"/"4e0"/"+4"/
43
+ * "4.0", which would route those straight to create-new — the same
44
+ * non-canonical-input-hits-the-destructive-branch bug in a new coat.
45
+ */
46
+ export async function pick(label, items, render, askFn = ask) {
30
47
  if (!items.length)
31
48
  return undefined;
32
49
  console.log(`\n${label}:`);
33
50
  items.forEach((it, i) => console.log(` ${i + 1}) ${render(it)}`));
34
- console.log(` ${items.length + 1}) + create new`);
35
- const a = await ask("Choose a number: ");
36
- const n = Number(a);
37
- if (Number.isInteger(n) && n >= 1 && n <= items.length)
38
- return items[n - 1];
39
- return undefined; // create-new (or invalid → treated as create)
51
+ const createNew = items.length + 1;
52
+ console.log(` ${createNew}) + create new`);
53
+ for (let attempt = 0; attempt < 3; attempt++) {
54
+ const a = await askFn("Choose a number: ");
55
+ if (/^\d+$/.test(a)) {
56
+ const n = Number(a);
57
+ if (n >= 1 && n <= items.length)
58
+ return items[n - 1];
59
+ if (n === createNew)
60
+ return undefined;
61
+ }
62
+ console.log(`Please enter a number between 1 and ${createNew}.`);
63
+ }
64
+ throw new Error("no valid choice — aborting");
40
65
  }
41
66
  export async function bindAction(opts) {
42
67
  const cfg = loadConfig();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retasc/cli",
3
- "version": "1.6.1",
3
+ "version": "1.6.3",
4
4
  "description": "Retasc CLI — sign in with GitHub, 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": {