@retasc/cli 1.25.0 → 1.26.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/CHANGELOG.md CHANGED
@@ -6,6 +6,21 @@ 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.26.0 (2026-08-19)
10
+
11
+ - **RTSC-670** — `retasc bind` can sign you in again. It has opened with the device flow
12
+ since 1.20-era, but a leftover session guard in the command wrapper exited first, so on
13
+ a machine that had never signed in — the only state a new owner is ever in — `bind`
14
+ printed "Not signed in" and stopped. Owner onboarding dead-ended at its first
15
+ documented command, on every release for three weeks. The guard was correct when it was
16
+ written and became redundant the moment `bind` grew its own sign-in; nothing noticed
17
+ because no test ran the CLI with no session. Four now do.
18
+ - **RTSC-671** — errors name the command you actually ran. Told to `npx @retasc/cli bind`
19
+ and then answered with "Run `retasc login` first", you were pointed at a binary that
20
+ invocation never installs — a recoverable stumble turned into a dead end. Every "run X
21
+ first" message now renders `npx -y @retasc/cli@<version> …` or `retasc …` to match how
22
+ you started it.
23
+
9
24
  ## 1.25.0 (2026-08-19)
10
25
 
11
26
  - **RTSC-669** — the invite project picker takes several projects. 1.24.0 shipped it
package/dist/api.js CHANGED
@@ -2,6 +2,8 @@ import { ConvexHttpClient } from "convex/browser";
2
2
  import { makeFunctionReference } from "convex/server";
3
3
  import { loadConfig } from "./config.js";
4
4
  import { refreshSession, deviceLogin } from "./auth.js";
5
+ import { selfCommand } from "./lib/launcher.js";
6
+ import { VERSION } from "./version.js";
5
7
  // Typed-ish references to the public management functions in convex/manage.ts.
6
8
  // The CLI is a standalone package, so we reference functions by name rather than
7
9
  // importing the parent's generated api.
@@ -163,7 +165,7 @@ async function withAuth(call) {
163
165
  if (await refreshSession())
164
166
  return await call();
165
167
  if (!process.stdout.isTTY) {
166
- throw new Error("Session expired and could not refresh. Run `retasc login`.");
168
+ throw new Error(`Session expired and could not refresh. Run \`${selfCommand(VERSION)} login\`.`);
167
169
  }
168
170
  console.error("Session expired — re-authenticating with GitHub…");
169
171
  await deviceLogin();
@@ -493,7 +493,7 @@ export async function ensureSignedIn() {
493
493
  if (loadConfig().token)
494
494
  return;
495
495
  if (!isInteractive()) {
496
- throw new Error("Not signed in. Run `retasc login` first (no TTY here for the device flow).");
496
+ throw new Error(`Not signed in. Run \`${selfCommand(VERSION)} login\` first (no TTY here for the device flow).`);
497
497
  }
498
498
  // RTSC-508: don't name a provider here. `deviceLogin` asks which door, and
499
499
  // announcing "GitHub" before the question would be wrong for the invited
@@ -1,6 +1,8 @@
1
1
  import { api } from "../api.js";
2
2
  import { clean } from "../lib/text.js";
3
3
  import { isInteractive } from "./bind.js";
4
+ import { selfCommand } from "../lib/launcher.js";
5
+ import { VERSION } from "../version.js";
4
6
  import { identityLoop } from "./join.js";
5
7
  /**
6
8
  * Which org's placeholders to offer.
@@ -65,7 +67,7 @@ function report(outcome, orgLabel) {
65
67
  console.log("Noted. That covers those tools only, so a later import will ask again.");
66
68
  return;
67
69
  case "left":
68
- console.log("Nothing linked. Run `retasc identity` again whenever you want to look.");
70
+ console.log(`Nothing linked. Run \`${selfCommand(VERSION)} identity\` again whenever you want to look.`);
69
71
  return;
70
72
  case "skipped":
71
73
  // Only reachable non-interactively; the interactive guard below catches that first.
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from "commander";
3
3
  import { VERSION } from "./version.js";
4
+ import { selfCommand } from "./lib/launcher.js";
4
5
  import { loadConfig, patchConfig, saveConfig, configPath, isLoggedIn } from "./config.js";
5
6
  import { installMcp, normalizeScope } from "./commands/mcp.js";
6
7
  import { installGate, resolveGatePrefix } from "./commands/gate.js";
@@ -25,7 +26,10 @@ program
25
26
  .version(VERSION);
26
27
  function requireLogin() {
27
28
  if (!isLoggedIn()) {
28
- console.error("Not signed in. Run `retasc login` first.");
29
+ // RTSC-671 — `selfCommand` renders the form they actually used. The docs send a
30
+ // new owner through `npx @retasc/cli`, which never puts `retasc` on PATH, so naming
31
+ // it here answers a failure with a second `command not found`.
32
+ console.error(`Not signed in. Run \`${selfCommand(VERSION)} login\` first.`);
29
33
  process.exit(1);
30
34
  }
31
35
  }
@@ -87,7 +91,7 @@ program
87
91
  // confirm scope before any work. Resolved from the local key, server-enforced.
88
92
  const local = readLocalBinding(process.cwd());
89
93
  if (local?.markerOnly) {
90
- console.log("This folder → has a Retasc marker but no key on this machine. Run `retasc bind`.\n");
94
+ console.log(`This folder → has a Retasc marker but no key on this machine. Run \`${selfCommand(VERSION)} bind\`.\n`);
91
95
  }
92
96
  else if (local) {
93
97
  try {
@@ -107,10 +111,10 @@ program
107
111
  }
108
112
  }
109
113
  else {
110
- console.log("This folder → not bound. Run `retasc bind`.\n");
114
+ console.log(`This folder → not bound. Run \`${selfCommand(VERSION)} bind\`.\n`);
111
115
  }
112
116
  if (!isLoggedIn()) {
113
- console.log("Not signed in (management). Run `retasc login` to manage orgs/projects.");
117
+ console.log(`Not signed in (management). Run \`${selfCommand(VERSION)} login\` to manage orgs/projects.`);
114
118
  return;
115
119
  }
116
120
  try {
@@ -200,7 +204,16 @@ program
200
204
  await setupFromToken(opts.setup, opts).catch(fail);
201
205
  return;
202
206
  }
203
- requireLogin();
207
+ // NO requireLogin here (RTSC-670). `bindAction` opens with `ensureSignedIn`, which
208
+ // runs the device flow when there is no session — that IS the documented first step
209
+ // of owner onboarding, and it is the only state a new owner is ever in. This guard
210
+ // predated that (it was correct in 285ec74, when bindAction had no sign-in of its
211
+ // own) and `ensureSignedIn` arriving in 72182c3 left it in front of a door it
212
+ // permanently closed: every `bind` on a fresh machine exited 1 before reaching it.
213
+ //
214
+ // `ensureSignedIn` also refuses BETTER — it says why ("no TTY here for the device
215
+ // flow") where this said only that you weren't signed in, which is the diagnosis
216
+ // that sends someone looking in the wrong place.
204
217
  await bindAction(opts).catch(fail);
205
218
  });
206
219
  // `retasc doctor` — verify this folder's binding + flag any illegal global server.
@@ -527,7 +540,7 @@ gate
527
540
  if (r.source !== "--prefix")
528
541
  console.log(`Prefix ${r.prefix} — from ${r.source}.`);
529
542
  if (r.source === "global config") {
530
- console.log(" (This folder isn't bound — `retasc bind` makes the prefix folder-scoped.)");
543
+ console.log(` (This folder isn't bound — \`${selfCommand(VERSION)} bind\` makes the prefix folder-scoped.)`);
531
544
  }
532
545
  if (r.shadowedDefault) {
533
546
  console.log(` ⚠ Ignoring global default prefix ${r.shadowedDefault} — this folder's binding wins.`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retasc/cli",
3
- "version": "1.25.0",
3
+ "version": "1.26.0",
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": {