@retasc/cli 1.19.0 → 1.21.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 +17 -1
- package/README.md +1 -1
- package/dist/commands/billing.js +4 -2
- package/dist/commands/bind.js +2 -2
- package/dist/commands/import.js +10 -3
- package/dist/commands/join.js +3 -2
- package/dist/index.js +4 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,22 @@ 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.21.0 (2026-08-07)
|
|
10
|
+
|
|
11
|
+
- **RTSC-527** — the re-import warning dates the last import in **your** timezone. The day
|
|
12
|
+
was formatted from `toISOString()`, which rolls back one east of Greenwich: at UTC+7 an
|
|
13
|
+
import made five hours ago read as yesterday's, which is the opposite of useful for a line
|
|
14
|
+
whose job is to say how long ago it was. The Dash gained the same date in the same shape
|
|
15
|
+
in this release, and moved onto the same durable per-source history the CLI already read,
|
|
16
|
+
so the two surfaces now describe one import the same way.
|
|
17
|
+
|
|
18
|
+
## 1.20.0 (2026-08-04)
|
|
19
|
+
|
|
20
|
+
- **RTSC-561** — the org gained an **admin** role, and the CLI stopped refusing it.
|
|
21
|
+
`retasc billing` gated on `role !== "owner"` client-side, so it would have refused an
|
|
22
|
+
admin locally for a call the server allows. Owner-only copy in `bind` and the command
|
|
23
|
+
help now names both roles.
|
|
24
|
+
|
|
9
25
|
## 1.19.0 (2026-08-03)
|
|
10
26
|
|
|
11
27
|
- **RTSC-495** — `retasc bind --setup <code>` sets a folder up with no sign-in and nothing
|
|
@@ -529,7 +545,7 @@ there is no TTY to run one in.
|
|
|
529
545
|
|
|
530
546
|
- **RTSC-263** — owner/member permission denials now print a readable reason and the
|
|
531
547
|
next step instead of an opaque `Server Error`. Hitting an owner-only command as a
|
|
532
|
-
member reports "Owner role required." with "Ask
|
|
548
|
+
member reports "Owner role required." with "Ask `<owner>` to create a project." on its
|
|
533
549
|
own line. The backend change does the work; the CLI already read the structured
|
|
534
550
|
payload (1.5.0), so this release carries only the hardening below.
|
|
535
551
|
- **RTSC-263** — `formatError` now strips U+0085, U+2028 and U+2029 in addition to the
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# retasc
|
|
2
2
|
|
|
3
|
-
**The issue tracker
|
|
3
|
+
**The issue tracker that hands your backlog to AI agents.**
|
|
4
4
|
|
|
5
5
|
Over [MCP](https://modelcontextprotocol.io), a heterogeneous fleet of agents atomically
|
|
6
6
|
claims unblocked, prioritized tasks and runs in parallel — server-enforced, no collisions.
|
package/dist/commands/billing.js
CHANGED
|
@@ -44,8 +44,10 @@ export async function billingAction(opts) {
|
|
|
44
44
|
const org = me.orgs.find((o) => o.id === orgId);
|
|
45
45
|
orgLabel = org ? `${org.name}${org.slug ? ` (${org.slug})` : ""}` : String(orgId);
|
|
46
46
|
// Fail early with the actionable message rather than a raw FORBIDDEN from the server.
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
// Owner OR admin (RTSC-561) — this mirrors `requireOwnerOrAdmin`, and a stale copy of
|
|
48
|
+
// the rule here would refuse an admin locally for a call the server would have allowed.
|
|
49
|
+
if (org && org.role !== "owner" && org.role !== "admin") {
|
|
50
|
+
throw new Error(`Billing needs the owner or admin role — yours in ${orgLabel} is "${org.role}".`);
|
|
49
51
|
}
|
|
50
52
|
const [status, charges] = await Promise.all([
|
|
51
53
|
api.billingStatus({ orgId: orgId }),
|
package/dist/commands/bind.js
CHANGED
|
@@ -286,7 +286,7 @@ export async function completeWorkspaceSetup(args) {
|
|
|
286
286
|
let prefix;
|
|
287
287
|
if (!projectId && opts.project && opts.prefix) {
|
|
288
288
|
if (!args.canCreateProject) {
|
|
289
|
-
cliError("FORBIDDEN", "Only an owner can create a project.", `Ask
|
|
289
|
+
cliError("FORBIDDEN", "Only an owner or admin can create a project.", `Ask one of them to add one, then pass --project-id <id>.`);
|
|
290
290
|
}
|
|
291
291
|
const p = (await api.createProject({ orgId, name: opts.project, prefix: opts.prefix }));
|
|
292
292
|
projectId = p.projectId;
|
|
@@ -301,7 +301,7 @@ export async function completeWorkspaceSetup(args) {
|
|
|
301
301
|
// what to ask for, by name. A bare FORBIDDEN from `createProject` would be both
|
|
302
302
|
// wrong (they never asked to create anything) and unactionable.
|
|
303
303
|
if (!list.length) {
|
|
304
|
-
cliError("NO_PROJECTS", `Org ${org} has no projects yet, and only an owner can create one.`, `Ask
|
|
304
|
+
cliError("NO_PROJECTS", `Org ${org} has no projects yet, and only an owner or admin can create one.`, `Ask one of them to add a project, then finish this folder with: ${selfCommand(VERSION)} bind --org-id ${orgId}`);
|
|
305
305
|
}
|
|
306
306
|
// One project is not a choice. Asking anyway would be the only question in the
|
|
307
307
|
// common invite path, for an answer that was never in doubt.
|
package/dist/commands/import.js
CHANGED
|
@@ -18,6 +18,11 @@ const GROUP_LABEL = {
|
|
|
18
18
|
};
|
|
19
19
|
/** Section order, matching the Dash. */
|
|
20
20
|
const GROUP_ORDER = ["not_started", "active", "done", "closed"];
|
|
21
|
+
/** `YYYY-MM-DD` in the local zone. Mirrored in `dash/src/lib/importGating.ts`. */
|
|
22
|
+
function localDay(d) {
|
|
23
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
24
|
+
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
|
25
|
+
}
|
|
21
26
|
/**
|
|
22
27
|
* What to say before a SECOND import into the same org (RTSC-526).
|
|
23
28
|
*
|
|
@@ -36,9 +41,11 @@ export function reimportWarning(history, source, label) {
|
|
|
36
41
|
const prior = history.find((h) => h.source === source);
|
|
37
42
|
if (!prior)
|
|
38
43
|
return null;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
// The reader's day, not UTC (RTSC-527). `toISOString().slice(0, 10)` was the original
|
|
45
|
+
// and it misdates by one: at UTC+7 an import made before 07:00 local prints as
|
|
46
|
+
// yesterday, which is the opposite of useful for a line whose whole job is "how long
|
|
47
|
+
// ago". The Dash's `importDay` formats identically, so one import still gets one date.
|
|
48
|
+
const when = prior.lastImportedAt ? ` (last on ${localDay(new Date(prior.lastImportedAt))})` : "";
|
|
42
49
|
return (`\n! You've imported from ${clean(label)} into this org before${when}.\n` +
|
|
43
50
|
` Re-importing re-syncs those issues, so any edits you made in Retasc to them\n` +
|
|
44
51
|
` (status, labels, and so on) will be replaced by ${clean(label)}'s version.`);
|
package/dist/commands/join.js
CHANGED
|
@@ -223,8 +223,9 @@ export async function joinAction(link, opts) {
|
|
|
223
223
|
orgLabel,
|
|
224
224
|
opts,
|
|
225
225
|
existing: guard.existing,
|
|
226
|
-
// `createProject` is `
|
|
227
|
-
//
|
|
226
|
+
// `createProject` is `requireOwnerOrAdmin`, and an invite only ever grants `member`
|
|
227
|
+
// (admin is granted by `setMemberRole` after joining, never by a bearer code —
|
|
228
|
+
// RTSC-561). Offering "+ create new" here would be offering a refusal as a choice.
|
|
228
229
|
canCreateProject: false,
|
|
229
230
|
});
|
|
230
231
|
}
|
package/dist/index.js
CHANGED
|
@@ -211,7 +211,7 @@ program
|
|
|
211
211
|
});
|
|
212
212
|
program
|
|
213
213
|
.command("billing")
|
|
214
|
-
.description("Show the org's billing: subscription, what's owed now, and the charge + on-chain payment history across every payment link ever used (owner
|
|
214
|
+
.description("Show the org's billing: subscription, what's owed now, and the charge + on-chain payment history across every payment link ever used (owner or admin).")
|
|
215
215
|
.option("--org-id <id>", "Which org (defaults to your only one).")
|
|
216
216
|
.option("--json", "Emit the raw payload instead of the summary.")
|
|
217
217
|
.action(async (opts) => {
|
|
@@ -356,7 +356,7 @@ key
|
|
|
356
356
|
const members = program.command("members").description("Invite people to an org and manage invites.");
|
|
357
357
|
members
|
|
358
358
|
.command("invite")
|
|
359
|
-
.description("Mint a single-use invite code for an org (owner
|
|
359
|
+
.description("Mint a single-use invite code for an org (owner or admin). Shown once.")
|
|
360
360
|
.requiredOption("--org-id <id>")
|
|
361
361
|
.option("--expires-days <n>", "Days until the code expires (1–30, default 7)", (v) => parseInt(v, 10))
|
|
362
362
|
.action(async (opts) => {
|
|
@@ -377,7 +377,7 @@ members
|
|
|
377
377
|
});
|
|
378
378
|
members
|
|
379
379
|
.command("list")
|
|
380
|
-
.description("List an org's invites and their status (owner
|
|
380
|
+
.description("List an org's invites and their status (owner or admin).")
|
|
381
381
|
.requiredOption("--org-id <id>")
|
|
382
382
|
.option("--json", "Emit the raw payload instead of the table.")
|
|
383
383
|
.action(async (opts) => {
|
|
@@ -392,7 +392,7 @@ members
|
|
|
392
392
|
});
|
|
393
393
|
members
|
|
394
394
|
.command("revoke")
|
|
395
|
-
.description("Revoke an unused invite (owner
|
|
395
|
+
.description("Revoke an unused invite (owner or admin).")
|
|
396
396
|
.requiredOption("--invite-id <id>")
|
|
397
397
|
.action(async (opts) => {
|
|
398
398
|
requireLogin();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@retasc/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.21.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": {
|