@retasc/cli 1.13.0 → 1.14.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 ADDED
@@ -0,0 +1,555 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@retasc/cli` are recorded here, newest first. Every version
4
+ published to npm has an entry; the ones predating this file were reconstructed from the
5
+ release commits and the issues they reference.
6
+
7
+ Dates are the npm publish date. Each entry names the RTSC issue behind it.
8
+
9
+ ## 1.14.0 (2026-08-02)
10
+
11
+ - **RTSC-523** — setup asks before installing anything on your machine.
12
+
13
+ `retasc bind` and `retasc join` are one command you paste and answer, and somewhere in the
14
+ middle they ran `npm install -g @retasc/cli`. It said so, but it never asked. That is the
15
+ only step in a folder-scoped command that changes the machine rather than the folder, and
16
+ a shared npm prefix is exactly what plenty of developers keep clean.
17
+
18
+ ```
19
+ Install the retasc command on this machine?
20
+
21
+ 1) Yes, globally A `retasc` command you can use anywhere.
22
+ Best if you'll use Retasc in more than one project.
23
+ 2) No, run it on demand Nothing is installed. Your agent fetches it when it
24
+ starts, which adds a couple of seconds and needs a
25
+ network connection.
26
+ ```
27
+
28
+ Both answers leave the folder bound identically. Option 2 is not a per-project install:
29
+ nothing is written to the folder, so it needs no `package.json` and cannot fail for want
30
+ of an npm project. Your answer is remembered, because it is a question about the machine
31
+ and the machine has not changed by the time you bind a second folder.
32
+
33
+ You are only asked when it would actually happen. If `retasc` already works, there is
34
+ nothing to decide and nothing is said.
35
+
36
+ **Without a TTY it installs, exactly as before.** That is deliberate rather than a
37
+ leftover: when an agent runs setup on someone's behalf, that person never types `retasc`,
38
+ but their agent starts the MCP server every session, and the on-demand route would cost
39
+ them seconds and a network dependency every single time. `--no-install` on `bind` and
40
+ `join` declines without a TTY, for a developer whose own agent is doing the setup.
41
+
42
+ ## 1.13.1 (2026-08-02)
43
+
44
+ - **RTSC-522** — the changelog is public, and five releases that were never written down now
45
+ are.
46
+
47
+ It used to be unreachable by anyone who installs the CLI: it did not ship in the tarball,
48
+ the README never mentioned it, and the source repo is private so the npm repository link
49
+ 404s for the public. It is now at
50
+ [docs.retasc.com/changelog](https://docs.retasc.com/changelog), and ships in the package.
51
+
52
+ 1.1.0, 1.1.1, 1.1.3, 1.2.1 and 1.2.2 were published and never described. They are
53
+ reconstructed here from their release commits and the issues they reference, so every
54
+ version on npm now has an entry. Each one carries its publish date.
55
+
56
+ Also fixed two npm-facing details: the package description still said "sign in with
57
+ GitHub", which stopped being the whole truth at 1.11.0, and the bug-report link pointed at
58
+ a private repository that 404s for everyone npm showed it to.
59
+
60
+ ## 1.13.0 (2026-08-02)
61
+
62
+ - **RTSC-521** — five commands stopped answering you with a JSON dump.
63
+
64
+ `whoami`, `org create`, `project create`, `key list` and `members list` printed the raw
65
+ payload. `whoami` is the one people actually noticed, because it is the command you run to
66
+ find out who you are:
67
+
68
+ ```
69
+ {
70
+ "orgs": [],
71
+ "user": {
72
+ "email": "you@example.com",
73
+ "id": "mh7edhnpet55dqr9m48yked29s8bqr9j",
74
+ "name": "Your Name"
75
+ }
76
+ }
77
+ ```
78
+
79
+ The one fact you wanted was a bracket to parse, next to a document id that means nothing.
80
+ Now:
81
+
82
+ ```
83
+ Signed in Your Name <you@example.com>
84
+ Orgs none
85
+ ```
86
+
87
+ `key list` and `members list` are aligned tables, and state reads as words: a revoked key
88
+ says `revoked` rather than an epoch, and a spent invite shows no expiry date because the
89
+ date stopped meaning anything. Auto-minted session keys are folded into a count instead of
90
+ drowning the keys you can actually manage.
91
+
92
+ Ids follow one rule: shown when a command takes them, dropped when nothing does. So
93
+ `org create` gives you the org id and names the command that wants it, and never mentions
94
+ `ownerMemberId`.
95
+
96
+ **`--json` on all five, emitting exactly what they printed before.** Anything scripted
97
+ against the old output keeps working by adding the flag.
98
+
99
+ `whoami`'s binding block is unchanged. It was already the useful half.
100
+
101
+ ## 1.12.0 (2026-08-02)
102
+
103
+ - **RTSC-519** — `retasc bind` now tells you it finished, and what to do next.
104
+
105
+ It used to end on the last thing it *did* ("This folder is bound to org Acme / project
106
+ ACM") and stop. So the person who set up their own org was left reading a status line and
107
+ guessing whether anything else was required, while the invited teammate, who arrives
108
+ through `retasc join`, was told. Both commands now end the same way:
109
+
110
+ ```
111
+ Start your agent in this folder, or restart it if it's already open, and it'll pull from the queue.
112
+ ```
113
+
114
+ The restart half matters: `.mcp.json` is read when an MCP client starts, so an agent
115
+ already open on that folder won't see Retasc until it restarts — and `bind` is routinely
116
+ run from inside a session that's already there.
117
+
118
+ The sentence lives in the tail both commands share, rather than a copy in each, so
119
+ neither can lose it again.
120
+
121
+ - **RTSC-507** — "none of these are me" now covers the tools you were asked about, not the
122
+ whole org forever.
123
+
124
+ Declining wrote one org-wide flag, checked before the list of imported people was even
125
+ read. So the January answer "I was never in ClickUp" — correct, and the cheapest possible
126
+ answer to give — meant that when the org migrated off Jira in June, where you *did* have
127
+ an account, you were never offered your placeholder. Not by `retasc identity`, not by
128
+ `retasc join`, not by the Dash, not ever. Your Jira authorship, comments and assignments
129
+ stayed on a placeholder permanently, and only an owner could repair it.
130
+
131
+ Claiming was already tracked per source, so someone who *claimed* their ClickUp identity
132
+ was correctly re-asked at every later migration. Declining being the more final of the two
133
+ was backwards.
134
+
135
+ The decline row now names what it covers:
136
+
137
+ ```
138
+ 3) None of these are me (covers ClickUp and Jira only)
139
+ ```
140
+
141
+ and `retasc identity` says so when nothing is left:
142
+
143
+ ```
144
+ You've answered about every tool imported into Acme so far.
145
+ Run this again after the next migration, each one is asked about separately.
146
+ ```
147
+
148
+ That replaces wording saying the answer "covers the whole org, including later
149
+ migrations" and pointing at an owner. It existed only to describe this bug.
150
+
151
+ **Needs the matching backend deploy.** The copy above is a promise the server keeps, so
152
+ publish this only after `convex deploy` and `migrations:backfillDismissedSources` have
153
+ run. Against an older backend the CLI would say a later import will ask again, and it
154
+ would not.
155
+
156
+ ## 1.11.0 (2026-08-02)
157
+
158
+ - **RTSC-508** — you can now sign in with **Google**, not only GitHub.
159
+
160
+ Google sign-in shipped for the web Dash first, which left a one-way street: an account
161
+ created through that door reached the Dash and nothing else, because every login-gated
162
+ command here sat behind a GitHub-only device flow. `retasc login` would start a GitHub
163
+ device flow for an account GitHub had never heard of. That blocked `bind`, `init`, `key`,
164
+ `members`, `billing` and `identity` outright — including the sign-in step *inside*
165
+ `retasc bind` and `retasc join`, so a teammate invited through the web could not finish
166
+ setting up their folder at all.
167
+
168
+ With no flag, `login` now asks which door you use:
169
+
170
+ ```
171
+ How do you sign in to Retasc?
172
+ 1) GitHub
173
+ 2) Google
174
+ Choose a number:
175
+ ```
176
+
177
+ After a successful sign-in the door is remembered, so later logins offer it back and
178
+ Enter takes it:
179
+
180
+ ```
181
+ How do you sign in to Retasc?
182
+ 1) GitHub
183
+ 2) Google (last used)
184
+ Choose a number [2]:
185
+ ```
186
+
187
+ A default only ever appears once it is a recorded fact about you. On a first login there
188
+ is none, and Enter is not an answer — because the wrong door is not a mistake you correct
189
+ next time (see below). The remembered door is a default, not a lock: the other one is
190
+ still one keystroke, and a typo re-prompts rather than being read as "the usual".
191
+
192
+ `retasc login --google` / `--github` skip the question. A non-interactive run is
193
+ unchanged: no prompt, GitHub, exactly as before. The same question appears inside `bind`
194
+ and `join` when they sign you in for you.
195
+
196
+ **Signing in through the wrong door is not a typo you correct on the next run.** Google
197
+ and GitHub are deliberately separate identities — doors are linked only on a provider's
198
+ own immutable account id, never on a matching email address, because email is an
199
+ account-takeover vector. So a Google sign-in by someone who already has a GitHub account
200
+ here creates a *second* identity with its own membership, and the CLI cannot merge them
201
+ back. That is why the question is asked rather than guessed, and why a non-answer
202
+ re-prompts instead of falling through to a door.
203
+
204
+ Needs `AUTH_GOOGLE_DEVICE_ID` / `AUTH_GOOGLE_DEVICE_SECRET` on the deployment
205
+ (`operations/runbooks/google-device-client.md`). Where they aren't set, the CLI says so
206
+ in one line and names GitHub as the way in meanwhile, rather than failing opaquely.
207
+
208
+ ## 1.10.0 (2026-08-01)
209
+
210
+ - **RTSC-477** — new command: `retasc identity`. It shows the people a migration carried
211
+ into your org and asks which one is you — the same question `retasc join` asks, on demand.
212
+
213
+ ```
214
+ retasc identity # defaults to your only org
215
+ retasc identity --org-id … # when you're in several
216
+ ```
217
+
218
+ `join` asks this once, at the moment you accept an invite. Placeholders arrive with
219
+ *every* migration, though, and claiming is per source tool rather than per person: the
220
+ backend is built for "claim your ClickUp one now, your Jira one in six months". So a team
221
+ that onboarded by CLI a year ago had no terminal path to a later import's history at all,
222
+ and had to open the Dash or leave it on placeholders. Three narrower cases `join` skips on
223
+ purpose are covered too: `--yes`, a non-interactive run, and `--no-bind`.
224
+
225
+ It asks the question, so it needs a TTY and refuses without one rather than exiting 0 in
226
+ silence. There is deliberately no `--yes` and no `identity claim <name>`: linking someone
227
+ pulls their authorship *and* their dispatch lane onto your account, irreversibly, with no
228
+ CLI way back, so it is never answered on a script's behalf.
229
+
230
+ It also names the ending, which `join` does not. "Nothing waiting for you" and "you've
231
+ already said none of these are you" are the same empty list from the inside and mean
232
+ opposite things — the second is permanent and org-wide, so it still applies after a later
233
+ migration that really did carry you across. That case now says so, and points at the
234
+ owner, who is the only one who can undo it.
235
+
236
+ ## 1.9.0 (2026-07-31)
237
+
238
+ **Behaviour change, read this if you script `join`:** `retasc join <code>` used to redeem an
239
+ invite and stop. It now also sets up the folder you run it in — mints a key, writes a
240
+ binding, wires the MCP marker. **`--no-bind` reproduces the old behaviour exactly**, same
241
+ output and same exit code. Every other command is unchanged.
242
+
243
+ `join` also no longer exits 1 telling you to run `retasc login` first. It starts the device
244
+ flow itself when there is no session, and refuses with the same message `bind` uses when
245
+ there is no TTY to run one in.
246
+
247
+ - **RTSC-492** — `retasc join` is now the whole of an invited teammate's setup, in one
248
+ command run from the folder their agent will work in:
249
+
250
+ ```
251
+ npx @retasc/cli join https://dash.retasc.com/join#rtscinv_…
252
+ ```
253
+
254
+ It signs them in (device flow, only when there is no session), redeems the invite,
255
+ offers them any identity a migration carried across, picks the project, makes `retasc`
256
+ durable, mints a key, binds the folder and wires the MCP marker. It used to be three
257
+ commands with an ordering trap in them, and the first of those three was `retasc login`
258
+ — which is not something you can tell someone who has installed nothing yet.
259
+
260
+ The target case is that an invited teammate never opens the Dash at all. With no imports
261
+ and one project, the only thing they type is the GitHub device code: every prompt is
262
+ conditional on there being a real choice.
263
+
264
+ - Takes a full invite link or a bare `rtscinv_…` code. The code is what the server
265
+ matches, so unwrapping a paste belongs at the edge that accepts typed input, not in the
266
+ mutation that grants membership.
267
+ - A member is never offered a project they cannot create (`createProject` is owner-only),
268
+ and an org with no projects names what to ask an owner for instead of failing opaquely.
269
+ - Imported placeholders are offered once per source tool, each behind an explicit
270
+ confirm, in the same words the Dash uses. `--yes` skips that question and never answers
271
+ it: claiming another person's history is irreversible and has no CLI path back.
272
+ - `--no-bind` keeps the old redeem-only behaviour for anything scripted against it.
273
+
274
+ Under it, `bind` and `join` now share one implementation of the folder half — the project
275
+ pick, the launcher ladder, the mint, the binding and the marker — so the fix that landed
276
+ in 1.8.0 cannot drift back out of one of them.
277
+
278
+ - **RTSC-498** — `retasc doctor` now says which platform the CLI is actually tested
279
+ on. Nothing in the product stated one: the READMEs never mentioned platforms and
280
+ `package.json` declares only `engines.node`, so someone hitting a problem on Linux
281
+ or Windows had no way to tell their own mistake from a bug from a platform we never
282
+ targeted. macOS is the only platform we run end to end.
283
+
284
+ It's a note in `doctor` rather than a line in the README on purpose. A README is read
285
+ by everyone, and for the majority on macOS a standing disclaimer about platforms they
286
+ aren't using is noise they read before they've even installed. `doctor` already knows
287
+ which machine it's on, so the people the limit applies to are exactly the people who
288
+ see it, and on macOS nothing is printed at all.
289
+
290
+ The note claims a limit, not a blockage: much of the CLI is plain Node and should work
291
+ fine, and `package.json` still carries no `os` field, so installing is never refused
292
+ anywhere Node 18+ runs. Windows and Linux are named as platforms we intend to support
293
+ properly; anything else is told it's untested without being promised a roadmap it
294
+ isn't on.
295
+
296
+ ## 1.8.0 (2026-07-31)
297
+
298
+ - **RTSC-493** — the MCP marker no longer names a command that may not exist. It
299
+ used to hardcode `retasc`, which is only on PATH after a global install — but the
300
+ Dash tells people to run `npx @retasc/cli bind`, and npx unpacks into its own cache
301
+ and installs nothing. So a bind printed every success line, really did bind the
302
+ folder, and left an agent that could not start the Retasc MCP server at all. The
303
+ failure surfaced later, somewhere else, as a broken server rather than a failed setup.
304
+
305
+ `bind` now resolves a launcher and **proves it by running it** before writing
306
+ anything: it uses an existing `retasc` if there is one, otherwise installs the CLI
307
+ globally, and if that install lands where PATH cannot see it, the marker names the
308
+ binary's absolute path instead. Only when none of that works does it fall back to a
309
+ version-pinned `npx`, which is slower and needs the network — and if even that will
310
+ not start, it says so outright rather than reporting success.
311
+
312
+ `retasc doctor` now checks the same thing, so a folder bound by an older version
313
+ reports why its agent cannot start and names the repair.
314
+
315
+ ## 1.7.2 (2026-07-21)
316
+
317
+ - **RTSC-297** — `retasc bind` no longer strands a new org silently. It creates
318
+ the org server-side before the project picker runs, so aborting at the project
319
+ step (reachable by a typo since 1.x's picker gives up after 3 bad answers) left
320
+ an org behind with no project, no key, and no local binding — invisible from
321
+ the CLI and quietly accruing on the billing rail. Bind now names the org and
322
+ prints the exact resume command (`retasc bind --org-id <id>`) when it aborts
323
+ before the workspace is bound. Selecting a pre-existing org and then aborting
324
+ is untouched — nothing is reclaimed.
325
+
326
+ ## 1.7.1 (2026-07-21)
327
+
328
+ - **RTSC-321** — the liveness watchdog now stops heartbeating an issue the moment
329
+ it moves to `review` (RTSC-257): the server releases the lease there, so the
330
+ proxy no longer pings a dead lease until the next heartbeat fails. It is treated
331
+ as a release, not a close — the branch/worktree is preserved for the review + PR
332
+ (never reaped). The reviewer's send-back (`review → todo`) still self-heals via
333
+ the failed-heartbeat path, since it can't be told apart from a `doing → todo`
334
+ edit by request args alone.
335
+
336
+ ## 1.7.0 (2026-07-21)
337
+
338
+ - **RTSC-306** — `retasc claim` / `retasc next` now pull **lane-scoped by
339
+ default**: only issues assigned to your principal or left unassigned, never
340
+ another human's work. The old `--mine` flag is retired — that behavior is the
341
+ default now. The new `--all-lanes` flag opts back into the whole ready pool
342
+ when you need to pick up an absent teammate's work. When your lane is empty but
343
+ ready work is stranded in another lane, the CLI says so and points you at
344
+ `--all-lanes` instead of reading as "nothing to do".
345
+
346
+ ## 1.6.3 (2026-07-20)
347
+
348
+ - **RTSC-266** — README now links the setup page, the docs quickstart, and the
349
+ parallel-agents guide instead of only the bare homepage. npm package pages are
350
+ a real entry point and only re-render on publish, so this ships as its own
351
+ patch release. No code changes.
352
+
353
+ ## 1.6.2 (2026-07-20)
354
+
355
+ - **RTSC-269** — `retasc bind`'s org/project picker no longer treats a typo as
356
+ "create new". Answering `1)` (a fumbled `1`) used to select nothing and fall
357
+ straight through to **creating a new org/project**, which then hit the owner
358
+ gate and surfaced as a redacted Server Error. Invalid input now re-prompts;
359
+ only the explicit trailing option creates. The answer must be plain digits, so
360
+ the non-canonical forms `Number()` happily parses (`0x4`, `4e0`, `+4`, `4.0`)
361
+ can't reach the create branch either.
362
+ - **RTSC-269** — the picker gives up after 3 invalid answers instead of looping,
363
+ and a closed stdin (Ctrl-D, or a pipe running dry) now exits with an error
364
+ rather than hanging. `readline.question()` never settles at EOF, so any prompt
365
+ in `bind` could previously wedge the CLI with no output and no exit.
366
+
367
+ ## 1.6.1 (2026-07-20)
368
+
369
+ - **RTSC-263** — owner/member permission denials now print a readable reason and the
370
+ next step instead of an opaque `Server Error`. Hitting an owner-only command as a
371
+ member reports "Owner role required." with "Ask <owner> to create a project." on its
372
+ own line. The backend change does the work; the CLI already read the structured
373
+ payload (1.5.0), so this release carries only the hardening below.
374
+ - **RTSC-263** — `formatError` now strips U+0085, U+2028 and U+2029 in addition to the
375
+ ASCII control characters. All three are mandatory line breaks, so a server message
376
+ interpolating a user-controlled name could previously forge extra lines in terminal
377
+ output.
378
+
379
+ ## 1.6.0 (2026-07-20)
380
+
381
+ - **RTSC-262** — `doctor` and `whoami` no longer report "not bound" for a folder whose
382
+ Retasc MCP is registered in **Claude Code local scope** (the `claude mcp add` default —
383
+ stored in Claude's own config, not `./.mcp.json`). The binding lookup now reads both
384
+ legal per-folder locations, and when both exist the **local-scope entry wins**, matching
385
+ Claude Code's documented precedence (local > project) — doctor names the org the agent
386
+ *actually* uses, and warns when a differing `./.mcp.json` marker is being shadowed.
387
+ - **RTSC-262** — `claim`/`tidy`/`done` resolve the key through the same entry selection,
388
+ so the CLI can no longer say "✓ bound" in one command and "No Retasc MCP key found" in
389
+ another for the same folder.
390
+ - **RTSC-262** — the illegal-global-server check is now **presence-based**: a hand-added
391
+ user-scope entry is detected in every shape (including keyless), and an unreadable
392
+ `~/.claude.json` reports "cannot verify" instead of a false all-clear.
393
+ - **RTSC-262** — honest failure modes: server-unreachable (timeouts, 5xx, rate limits) is
394
+ no longer reported as a rejected key, `whoami`/`doctor` requests are bounded by a 10s
395
+ timeout, and server-derived strings are stripped of control characters before printing.
396
+ - **RTSC-262** — `bind` hardening: re-binding to the *same* org/project is an idempotent
397
+ success (no key churn for provisioning scripts); replacing a *different* binding
398
+ non-interactively without `--yes` now fails loudly with exit 1 instead of silently
399
+ succeeding as a no-op; a cloned repo's committed marker no longer triggers the
400
+ replace prompt (minting your own key under it is what `bind` is for).
401
+ - **RTSC-262** — (security) a keystore-resolved key now only ever travels to the
402
+ keystore's own URL — a hostile `RETASC_MCP_URL` planted next to a committed secret-free
403
+ marker can no longer redirect a teammate's real key.
404
+
405
+ ## 1.5.0 (2026-07-20)
406
+
407
+ - **RTSC-261** — backend failures you're meant to act on now print what actually went
408
+ wrong instead of `✗ Server Error`. Convex masks any plain server throw in production, so
409
+ every precondition — a consumed invite code, an expired one, a suspended membership —
410
+ reached the terminal as the same opaque string. `retasc join` was the worst case: an
411
+ invited teammate hit an unreadable wall at the very first step.
412
+
413
+ Errors now carry a machine-readable `code`, a readable `message`, and an optional `hint`
414
+ printed on its own line:
415
+
416
+ ```
417
+ ✗ CONSUMED: This invite was already used.
418
+ → ask an owner for a fresh invite link
419
+ ```
420
+
421
+ This release covers invite redemption; the remaining surfaces (auth/key problems,
422
+ not-found lookups, billing gating, import/restore) follow. Internal invariants stay
423
+ masked deliberately — those are our bugs, not yours, and their messages describe server
424
+ state. **Upgrade before your teammates redeem invites**: an older CLI can't read the new
425
+ payload and prints it as raw JSON.
426
+
427
+ ## 1.4.0 (2026-07-19)
428
+
429
+ - **RTSC-279** — new `retasc billing` command: the org's whole billing picture in the
430
+ terminal instead of only in the Dash. Prints the subscription and spending caps, what's
431
+ owed right now, and the charge + confirmed on-chain payment history — both **org-scoped
432
+ across every payment link the org has ever used**, so changing payment link no longer
433
+ hides prior history. Owner-only (it reuses the same owner-gated functions the Dash
434
+ renders; the client-side role check is UX, the server still gates). `--org-id` selects the
435
+ org when you belong to more than one, `--json` emits the raw payload. Payments are a live
436
+ read of Xenarch's authoritative records and degrade to a note rather than failing the
437
+ command.
438
+ - **RTSC-279** — (server-side, no CLI change) the MCP usage meter now reports **two**
439
+ clearly-named figures instead of one misleading `wouldBeBillUsd`:
440
+ `lifetimeMeteredEstimateUsd` (all-time activity repriced at today's rate card — a
441
+ diagnostic, not an amount owed) and `pendingUsd` (what is actually owed right now, the
442
+ same figure the Dash shows). A new `billing_summary` MCP tool exposes the full billing
443
+ detail to agents whose human principal owns the org.
444
+
445
+ ## 1.3.2 (2026-07-17)
446
+
447
+ - **RTSC-250** — serialize `patchConfig` under a cross-process advisory lock so
448
+ concurrent CLI/MCP processes can't lose an update. Previously a lock-free
449
+ load-modify-save meant a `defaultOrgId`/`defaultProjectPrefix` write racing the
450
+ hourly token refresh could write back the old single-use `refreshToken`,
451
+ breaking the next refresh and forcing a device re-login a non-interactive
452
+ context can't perform. The lock re-reads the freshest config inside the
453
+ critical section and stamps a nonce so a stolen-from holder never deletes the
454
+ new owner's lock. Also sweeps orphaned `.config.json.<uuid>.tmp` files left by a
455
+ hard kill, age-gated so a concurrent writer's in-flight temp is never touched.
456
+
457
+ ## 1.3.1 (2026-07-17)
458
+
459
+ - **RTSC-179** — atomic config write (temp file + rename) so a reader never sees
460
+ a truncated `config.json`; adds `RETASC_DIR` support.
461
+ - **RTSC-178** — token refresh now classifies transient backend errors vs a
462
+ genuinely expired refresh token, so a one-off backend blip no longer drags a
463
+ valid session through a full device re-login.
464
+
465
+ ## 1.3.0 (2026-07-08)
466
+
467
+ - Auto-reap branches on MCP close: when the watchdog proxy observes a session's
468
+ own claim close terminally and successfully, it removes that issue's clean,
469
+ merged `rtsc-NN/*` worktree and branch out-of-band (`retasc tidy --prune --only
470
+ <id>`), instead of orphaning them until a human ran `retasc tidy`. Exposes
471
+ `tidy --only <RTSC-NN>`.
472
+
473
+ ## 1.2.4 (2026-07-07)
474
+
475
+ - **RTSC-170** — credential-file permission hardening: `config.json`,
476
+ `bindings.json`, and the fallback `.mcp.json` are written `0600` (dirs `0700`)
477
+ with no world-readable creation window.
478
+
479
+ ## 1.2.3 (2026-07-05)
480
+
481
+ - **RTSC-150** — watchdog `isClaimLost` fix: no longer drops a live lease when a
482
+ payload field merely contains the string `CLAIM_LOST`.
483
+
484
+ ## 1.2.2 (2026-07-04)
485
+
486
+ - **RTSC-148** — `retasc claim` takes the issue as a positional argument, and never
487
+ silently falls through to `next_issue`.
488
+
489
+ `retasc claim 143`, `claim RTSC-143` and `claim rtsc-143` all resolve to that issue; a
490
+ bare number expands against the *workspace's* prefix, resolved over the workspace key
491
+ rather than global config. Excess arguments now error loudly instead of being dropped by
492
+ Commander, which was how "claim this specific issue" quietly became "claim whatever is
493
+ next".
494
+
495
+ ## 1.2.1 (2026-07-04)
496
+
497
+ - **RTSC-143** — one tolerant tool-result parser, and a loud failure when the claim fence
498
+ is off.
499
+
500
+ The proxy and `claim` each had their own silent copy of the parser; they are now one
501
+ (`lib/toolresult.ts`), which recovers the leading JSON value when a footer trails the
502
+ payload, refuses to recover from an `isError` response or concatenated JSON, and warns on
503
+ stderr when it degrades so a shape regression is never silent.
504
+
505
+ Session-key minting retries once with a 5s timeout and checks `res.ok`. On a double
506
+ failure it still fails soft, but says loudly that the per-session claim fence is OFF, and
507
+ the proxy appends that notice to `whoami` so the agent sees the degraded state rather than
508
+ it sitting in an MCP log file nobody opens.
509
+
510
+ ## 1.2.0 (2026-07-04)
511
+
512
+ - **RTSC-137** — org-membership commands: `retasc members invite|list|revoke` and
513
+ `retasc join`.
514
+
515
+ ## 1.1.3 (2026-07-02)
516
+
517
+ - **RTSC-131** — `retasc --version` reads `package.json` instead of a frozen literal.
518
+
519
+ It was hardcoded to `1.1.1`, so the published 1.1.2 still reported 1.1.1. The version is
520
+ now read at runtime relative to the compiled file, making `package.json` the single source
521
+ of truth.
522
+
523
+ ## 1.1.2 (2026-07-02)
524
+
525
+ - **RTSC-130** — republish the bind auto-wire fix that had changed CLI source
526
+ without a version bump (npm versions are immutable).
527
+
528
+ ## 1.1.1 (2026-06-28)
529
+
530
+ - **RTSC-98** — `claim`, `tidy` and `done` resolve the keystore key through the same
531
+ resolver the proxy uses.
532
+
533
+ After 1.1.0 moved keys out of the repo, a secret-free `.mcp.json` was understood by the
534
+ proxy but not by those three commands, which still only knew the legacy inline-key path
535
+ and bailed with "No Retasc MCP key found". The two resolvers had drifted, so they are now
536
+ one (`resolveConn` in `lib/keystore.ts`): explicit `RETASC_MCP_KEY`, then a legacy inline
537
+ key, then the canonical secret-free marker. Legacy markers keep working.
538
+
539
+ ## 1.1.0 (2026-06-28)
540
+
541
+ - **RTSC-92** — workspace keys move to a home keystore, and the folder marker becomes
542
+ secret-free.
543
+
544
+ Secrets no longer sit in a project tree. The key lives in `~/.retasc/bindings.json` (mode
545
+ 0600), keyed by an opaque workspace id rather than a path, so nothing leaks a home
546
+ directory and a checkout stays portable across a team. What lands in the repo is a marker
547
+ carrying only that id, which is why `./.mcp.json` is safe to commit.
548
+
549
+ `doctor` reports whether a binding is keystore-backed or legacy, and flags a workspace id
550
+ already bound at a different folder. A cloned repo whose marker has no key on this machine
551
+ is reported as such rather than as broken.
552
+
553
+ ## 1.0.0 (2026-06-27)
554
+
555
+ - **RTSC-89** — initial npm publish as `@retasc/cli` (bin stays `retasc`).
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) · [Set up your agent](https://retasc.com/connect) · [Quickstart](https://docs.retasc.com/quickstart)
11
+ → [retasc.com](https://retasc.com) · [Set up your agent](https://retasc.com/connect) · [Quickstart](https://docs.retasc.com/quickstart) · [Changelog](https://docs.retasc.com/changelog)
12
12
 
13
13
  ## Install
14
14
 
@@ -18,6 +18,10 @@ npm i -g @retasc/cli
18
18
 
19
19
  This installs the `retasc` command. Requires Node.js ≥ 18.
20
20
 
21
+ Already installed? `retasc --version` tells you what you have, and
22
+ [the changelog](https://docs.retasc.com/changelog) says what changed since. Every published
23
+ version is listed there with a date.
24
+
21
25
  ## Quickstart
22
26
 
23
27
  ```sh
@@ -75,8 +79,9 @@ Run `retasc --help` or `retasc <command> --help` for the full set.
75
79
  - Website — [retasc.com](https://retasc.com)
76
80
  - Set up your agent — [retasc.com/connect](https://retasc.com/connect)
77
81
  - Docs + quickstart — [docs.retasc.com/quickstart](https://docs.retasc.com/quickstart)
82
+ - Changelog — [docs.retasc.com/changelog](https://docs.retasc.com/changelog)
78
83
  - Parallel agents guide — [retasc.com/guides/claude-code-parallel-agents](https://retasc.com/guides/claude-code-parallel-agents)
79
- - Issues — [github.com/Retasc/retasc/issues](https://github.com/Retasc/retasc/issues)
84
+ - Support — [support@retasc.com](mailto:support@retasc.com)
80
85
 
81
86
  ## License
82
87
 
@@ -1,10 +1,10 @@
1
1
  import { api, cliError } from "../api.js";
2
2
  import { deviceLogin } from "../auth.js";
3
- import { loadConfig } from "../config.js";
3
+ import { loadConfig, patchConfig } from "../config.js";
4
4
  import { installMarker } from "./mcp.js";
5
5
  import { readLocalBinding, resolveBinding } from "../lib/binding.js";
6
6
  import { getBinding, setBinding, newWorkspaceId } from "../lib/keystore.js";
7
- import { resolveLauncher, launcherNote, selfCommand } from "../lib/launcher.js";
7
+ import { resolveLauncher, launcherNote, runsOk, selfCommand } from "../lib/launcher.js";
8
8
  import { ask, confirm, isInteractive } from "../lib/prompt.js";
9
9
  import { clean } from "../lib/text.js";
10
10
  import { VERSION } from "../version.js";
@@ -151,6 +151,63 @@ export async function rebindGuard(args) {
151
151
  }
152
152
  return { proceed: false, existing };
153
153
  }
154
+ /**
155
+ * May we install `retasc` on this machine? (RTSC-523)
156
+ *
157
+ * Asked only when it would actually happen. `runsOk` is the same probe
158
+ * `resolveLauncher` opens with, so if `retasc` already works there is nothing to decide and
159
+ * a question would have exactly one possible outcome.
160
+ *
161
+ * A DEFAULT is right here, unlike the sign-in door (RTSC-508), which deliberately has none.
162
+ * A wrong answer costs a couple of seconds per agent start, not a second identity that
163
+ * cannot be merged back. The two questions look alike and are not.
164
+ *
165
+ * NO TTY ⇒ install, silently, exactly as before. That is not laziness about the default: it
166
+ * is the right answer for the person it affects most. The non-technical member of RTSC-497
167
+ * never opens a terminal — her AGENT runs this (RTSC-495/496), with no TTY. She will never
168
+ * type `retasc` herself, but her agent spawns the MCP server on every start, and the npx
169
+ * route would cost her seconds and a network dependency every single time, forever.
170
+ * `--no-install` exists for the developer who wants to decline without a TTY.
171
+ */
172
+ export async function chooseInstall(
173
+ /** `--no-install` ⇒ false. Undefined means "not stated". */
174
+ flag, deps = {}) {
175
+ if (flag === false)
176
+ return false;
177
+ const onPath = deps.onPath ?? (() => runsOk("retasc") !== null);
178
+ // Nothing to install, so nothing to ask.
179
+ if (onPath())
180
+ return true;
181
+ const remembered = (deps.remembered ?? (() => loadConfig().globalInstall))();
182
+ if (remembered !== undefined)
183
+ return remembered;
184
+ const interactive = deps.interactive ?? isInteractive;
185
+ if (!interactive())
186
+ return true;
187
+ console.log("\nInstall the retasc command on this machine?");
188
+ console.log(" 1) Yes, globally A `retasc` command you can use anywhere.");
189
+ console.log(" Best if you'll use Retasc in more than one project.");
190
+ console.log(" 2) No, run it on demand Nothing is installed. Your agent fetches it when it");
191
+ console.log(" starts, which adds a couple of seconds and needs a");
192
+ console.log(" network connection.");
193
+ const askFn = deps.askFn ?? ask;
194
+ for (let attempt = 0; attempt < 3; attempt++) {
195
+ const a = await askFn("Choose a number [1]: ");
196
+ // Either answer leaves this folder bound identically — only the machine differs — so
197
+ // an empty answer taking the default is safe here in a way it is not for the door.
198
+ if (a === "" || a === "1")
199
+ return remember(true);
200
+ if (a === "2")
201
+ return remember(false);
202
+ console.log("Please enter 1 or 2.");
203
+ }
204
+ throw new Error("no valid choice — aborting");
205
+ }
206
+ /** Record the answer, so binding a second folder does not re-ask about the same machine. */
207
+ function remember(globalInstall) {
208
+ patchConfig({ globalInstall });
209
+ return globalInstall;
210
+ }
154
211
  /**
155
212
  * Everything from "which project" to a working folder: pick the project, make `retasc`
156
213
  * durable, mint a key for that (org, project), write the binding, and wire the marker.
@@ -237,7 +294,15 @@ export async function completeWorkspaceSetup(args) {
237
294
  // name one proved to run on this machine. Resolved (and announced) here so the install
238
295
  // can't land after a key exists, and so every later message knows what to tell the user
239
296
  // to type.
240
- const launcher = resolveLauncher({ version: VERSION });
297
+ //
298
+ // RTSC-523 — and ASK first, because this is the one step in a folder-scoped command that
299
+ // changes the MACHINE. It used to just run `npm install -g`. The project already holds
300
+ // the opposite position everywhere else: `resolveLauncher` leaves a working `retasc`
301
+ // alone ("no surprise installs for someone who already manages their own"), and RTSC-520
302
+ // decided an update must ask. The first command a new developer runs was the one place
303
+ // we did it anyway.
304
+ const install = await chooseInstall(opts.install);
305
+ const launcher = resolveLauncher({ version: VERSION, install });
241
306
  const note = launcherNote(launcher);
242
307
  if (note)
243
308
  console.log(note);
package/dist/config.js CHANGED
@@ -61,6 +61,10 @@ export function loadConfig() {
61
61
  loginProvider: stored.loginProvider === "github" || stored.loginProvider === "google"
62
62
  ? stored.loginProvider
63
63
  : undefined,
64
+ // Same rule (RTSC-523): only a real boolean counts. Anything else reads as
65
+ // "never asked", so a mangled file leads to a question rather than to an
66
+ // install nobody agreed to.
67
+ globalInstall: typeof stored.globalInstall === "boolean" ? stored.globalInstall : undefined,
64
68
  };
65
69
  }
66
70
  /** Move a corrupt config aside to a unique sibling so a human can recover any
package/dist/index.js CHANGED
@@ -178,6 +178,10 @@ program
178
178
  .option("--agent <name>", "Agent member name (default: auto)")
179
179
  .option("--runtime <runtime>", "Agent runtime", "claude-code")
180
180
  .option("-y, --yes", "Don't prompt to confirm replacing an existing binding")
181
+ // RTSC-523 — decline the global install without a TTY. `bind`/`join` ask when a human
182
+ // is present; this is how a scripted run, or a developer whose own agent runs setup,
183
+ // says no up front instead of being installed onto.
184
+ .option("--no-install", "Don't install `retasc` on this machine; wire the pinned npx launcher instead")
181
185
  .action(async (opts) => {
182
186
  requireLogin();
183
187
  await bindAction(opts).catch(fail);
@@ -400,6 +404,10 @@ program
400
404
  // RTSC-477 — name the way back. `--yes` skips the identity question and must never answer
401
405
  // it, so the flag that causes the gap is the right place to say how to close it.
402
406
  .option("-y, --yes", "Don't prompt to replace an existing binding, and skip the identity question (ask it later with `retasc identity`)")
407
+ // RTSC-523 — decline the global install without a TTY. `bind`/`join` ask when a human
408
+ // is present; this is how a scripted run, or a developer whose own agent runs setup,
409
+ // says no up front instead of being installed onto.
410
+ .option("--no-install", "Don't install `retasc` on this machine; wire the pinned npx launcher instead")
403
411
  .allowExcessArguments(false)
404
412
  .action(async (link, opts) => {
405
413
  await joinAction(link, opts).catch(fail);
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "@retasc/cli",
3
- "version": "1.13.0",
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.",
3
+ "version": "1.14.0",
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": {
7
7
  "retasc": "dist/index.js"
8
8
  },
9
9
  "files": [
10
- "dist"
10
+ "dist",
11
+ "CHANGELOG.md"
11
12
  ],
12
13
  "engines": {
13
14
  "node": ">=18"
@@ -21,7 +22,8 @@
21
22
  "directory": "cli"
22
23
  },
23
24
  "bugs": {
24
- "url": "https://github.com/Retasc/retasc/issues"
25
+ "email": "support@retasc.com",
26
+ "url": "https://retasc.com"
25
27
  },
26
28
  "keywords": [
27
29
  "retasc",