transitions-agent 0.1.2 → 0.2.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.
@@ -2,6 +2,7 @@
2
2
  // transitions-agent: scan a codebase for missing or janky UI transitions.
3
3
  //
4
4
  // npx transitions-agent scan + motion score + findings
5
+ // npx transitions-agent signup free plan: sign up in the browser
5
6
  // npx transitions-agent signup you@x.co free plan: license key by email
6
7
  // npx transitions-agent fix propose AI fixes as diffs, confirm, apply
7
8
  // npx transitions-agent fix --pr after applying, open a pull request
@@ -25,7 +26,21 @@
25
26
  import { scan } from "../lib/scan.mjs";
26
27
  import { renderTerminal, renderMarkdown } from "../lib/report.mjs";
27
28
  import { runFix } from "../lib/fix.mjs";
28
- import { resolve } from "node:path";
29
+ import { resolve, join } from "node:path";
30
+ import { homedir } from "node:os";
31
+ import { readFileSync, writeFileSync } from "node:fs";
32
+ import { spawn } from "node:child_process";
33
+
34
+ const CREDS_PATH = join(homedir(), ".transitions-agent.json");
35
+ function loadCreds() {
36
+ try { return JSON.parse(readFileSync(CREDS_PATH, "utf8")); } catch { return null; }
37
+ }
38
+ function saveCreds(obj) { writeFileSync(CREDS_PATH, JSON.stringify(obj, null, 2)); }
39
+ function openBrowser(url) {
40
+ const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
41
+ try { spawn(cmd, [url], { stdio: "ignore", detached: true }).unref(); } catch { /* user opens manually */ }
42
+ }
43
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
29
44
 
30
45
  const args = process.argv.slice(2);
31
46
  const flags = {};
@@ -46,8 +61,44 @@ const api = (flags.api || process.env.TRANSITIONS_AGENT_API || "https://api.tran
46
61
 
47
62
  if (command === "signup") {
48
63
  const email = (positional[1] || "").trim();
64
+ if (!email) {
65
+ // Browser signup - works even when this terminal cannot ask questions
66
+ // (a coding agent's shell): the human types their email in the browser
67
+ // and this process polls until the key exists, then stores it.
68
+ let start;
69
+ try {
70
+ const res = await fetch(api + "/agent/signup/start", { method: "POST" });
71
+ if (!res.ok) throw new Error("start failed (" + res.status + ")");
72
+ start = await res.json();
73
+ } catch (e) {
74
+ console.error("Could not start browser signup: " + e.message);
75
+ console.error("Fallback: npx transitions-agent signup you@email.com");
76
+ process.exit(1);
77
+ }
78
+ console.log("Opening your browser to finish sign-up (code " + start.code + ").");
79
+ console.log("If it does not open: " + start.url);
80
+ openBrowser(start.url);
81
+ const deadline = Date.now() + (start.expires_in || 900) * 1000;
82
+ while (Date.now() < deadline) {
83
+ await sleep((start.interval || 3) * 1000);
84
+ let poll;
85
+ try { poll = await fetch(api + "/agent/signup/poll?secret=" + encodeURIComponent(start.secret)); }
86
+ catch { continue; }
87
+ if (poll.status === 202) continue;
88
+ const data = await poll.json().catch(() => ({}));
89
+ if (data.status === "ready" && data.license) {
90
+ saveCreds({ license: data.license, plan: data.plan || "free" });
91
+ console.log("\u2713 License key received and saved to " + CREDS_PATH);
92
+ console.log("You are set: npx transitions-agent fix");
93
+ process.exit(0);
94
+ }
95
+ if (data.status === "expired") break;
96
+ }
97
+ console.error("Sign-up timed out. Try again, or: npx transitions-agent signup you@email.com");
98
+ process.exit(1);
99
+ }
49
100
  if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
50
- console.error("Usage: transitions-agent signup you@company.com");
101
+ console.error("Usage: transitions-agent signup [you@company.com]");
51
102
  process.exit(1);
52
103
  }
53
104
  let res;
@@ -93,7 +144,7 @@ if (command === "fix") {
93
144
  console.log(renderTerminal(result));
94
145
  // No explicit mode + a human at the keyboard + a license that could use
95
146
  // either: ask. Agents and CI pass --mode (or get the polish default).
96
- const license = flags.license || process.env.TRANSITIONS_AGENT_LICENSE || "";
147
+ const license = flags.license || process.env.TRANSITIONS_AGENT_LICENSE || (loadCreds() || {}).license || "";
97
148
  if (!mode && license && process.stdin.isTTY && !flags.yes) {
98
149
  const readline = await import("node:readline");
99
150
  const answer = await new Promise((resolve) => {
package/lib/report.mjs CHANGED
@@ -77,6 +77,10 @@ export function renderMarkdown(result, opts = {}) {
77
77
  }
78
78
  lines.push("");
79
79
  lines.push("Run `npx transitions-agent` locally for details, or `npx transitions-agent fix` to get fixes as a pull request.");
80
+ if (opts.licenseCta) {
81
+ lines.push("");
82
+ lines.push("**Want these fixed automatically?** Add a `TRANSITIONS_AGENT_LICENSE` repo secret and the [fix workflow](https://github.com/Jakubantalik/transitions.dev/blob/main/agent/templates/transitions-fix.yml) - free key: `npx transitions-agent signup` · [plans](https://transitions.dev/pro.html)");
83
+ }
80
84
  return lines.join("\n");
81
85
  }
82
86
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "transitions-agent",
3
- "version": "0.1.2",
3
+ "version": "0.2.1",
4
4
  "description": "Scan your codebase for missing, janky, or inconsistent UI transitions. Get a motion score, ready-to-apply fixes from transitions.dev recipes, and an optional pull request with the fixes.",
5
5
  "type": "module",
6
6
  "bin": {