unfairly 0.8.2 → 0.8.4

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.
Files changed (218) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/LICENSE +15 -0
  3. package/README.md +3 -1
  4. package/dist/auth/browser-flow.d.ts +0 -1
  5. package/dist/auth/browser-flow.js +5 -81
  6. package/dist/cmd/connect.d.ts +0 -1
  7. package/dist/cmd/connect.js +1 -164
  8. package/dist/cmd/init.d.ts +0 -1
  9. package/dist/cmd/init.js +2 -138
  10. package/dist/cmd/invite.d.ts +0 -1
  11. package/dist/cmd/invite.js +4 -73
  12. package/dist/cmd/join.d.ts +0 -1
  13. package/dist/cmd/join.js +1 -91
  14. package/dist/cmd/login.d.ts +0 -1
  15. package/dist/cmd/login.js +3 -41
  16. package/dist/cmd/mcp.d.ts +0 -1
  17. package/dist/cmd/mcp.js +2 -86
  18. package/dist/cmd/pace.d.ts +23 -2
  19. package/dist/cmd/pace.js +4 -393
  20. package/dist/cmd/parse-share-input.d.ts +0 -1
  21. package/dist/cmd/parse-share-input.js +1 -56
  22. package/dist/cmd/pull.d.ts +0 -1
  23. package/dist/cmd/pull.js +7 -143
  24. package/dist/cmd/push.d.ts +0 -1
  25. package/dist/cmd/push.js +1 -85
  26. package/dist/cmd/resolve.d.ts +0 -1
  27. package/dist/cmd/resolve.js +1 -35
  28. package/dist/cmd/setup.d.ts +0 -1
  29. package/dist/cmd/setup.js +2 -345
  30. package/dist/cmd/status-card.d.ts +0 -1
  31. package/dist/cmd/status-card.js +2 -156
  32. package/dist/cmd/status.d.ts +0 -1
  33. package/dist/cmd/status.js +3 -29
  34. package/dist/cmd/watch.d.ts +0 -1
  35. package/dist/cmd/watch.js +1 -26
  36. package/dist/hosts/claude-code.d.ts +0 -1
  37. package/dist/hosts/claude-code.js +3 -180
  38. package/dist/hosts/claude-desktop.d.ts +0 -1
  39. package/dist/hosts/claude-desktop.js +3 -222
  40. package/dist/hosts/codex.d.ts +0 -1
  41. package/dist/hosts/codex.js +20 -234
  42. package/dist/hosts/shell-env.d.ts +0 -1
  43. package/dist/hosts/shell-env.js +9 -81
  44. package/dist/index.d.ts +0 -1
  45. package/dist/index.js +14 -206
  46. package/dist/lib/client.d.ts +0 -1
  47. package/dist/lib/client.js +1 -58
  48. package/dist/lib/events/emit.d.ts +0 -1
  49. package/dist/lib/events/emit.js +1 -28
  50. package/dist/lib/index.d.ts +0 -1
  51. package/dist/lib/index.js +1 -11
  52. package/dist/lib/transport.d.ts +0 -1
  53. package/dist/lib/transport.js +1 -85
  54. package/dist/lib/types/index.d.ts +0 -1
  55. package/dist/lib/types/index.js +1 -50
  56. package/dist/lib/vault/checkpoint.d.ts +0 -1
  57. package/dist/lib/vault/checkpoint.js +1 -18
  58. package/dist/lib/vault/read.d.ts +0 -1
  59. package/dist/lib/vault/read.js +1 -9
  60. package/dist/lib/vault/search.d.ts +0 -1
  61. package/dist/lib/vault/search.js +1 -10
  62. package/dist/pace/device.d.ts +3 -1
  63. package/dist/pace/device.js +2 -148
  64. package/dist/pace/enroll.d.ts +79 -0
  65. package/dist/pace/enroll.js +2 -0
  66. package/dist/pace/identity.d.ts +0 -1
  67. package/dist/pace/identity.js +1 -17
  68. package/dist/pace/install.d.ts +0 -1
  69. package/dist/pace/install.js +4 -127
  70. package/dist/pace/local-evidence.d.ts +0 -1
  71. package/dist/pace/local-evidence.js +2 -228
  72. package/dist/pace/local-sessions.d.ts +0 -1
  73. package/dist/pace/local-sessions.js +1 -254
  74. package/dist/pace/managed-config.d.ts +0 -1
  75. package/dist/pace/managed-config.js +8 -102
  76. package/dist/pace/normalize.d.ts +0 -1
  77. package/dist/pace/normalize.js +1 -293
  78. package/dist/pace/repository.d.ts +0 -1
  79. package/dist/pace/repository.js +2 -120
  80. package/dist/pace/schema.d.ts +0 -1
  81. package/dist/pace/schema.js +1 -134
  82. package/dist/pace/session-summary.d.ts +0 -1
  83. package/dist/pace/session-summary.js +2 -140
  84. package/dist/pace/spool.d.ts +0 -1
  85. package/dist/pace/spool.js +8 -87
  86. package/dist/pace-runtime.d.ts +1 -0
  87. package/dist/pace-runtime.js +2 -0
  88. package/dist/sync/api.d.ts +0 -1
  89. package/dist/sync/api.js +1 -55
  90. package/dist/sync/autoloader.d.ts +0 -1
  91. package/dist/sync/autoloader.js +5 -127
  92. package/dist/sync/conflict.d.ts +0 -1
  93. package/dist/sync/conflict.js +5 -15
  94. package/dist/sync/credentials.d.ts +0 -1
  95. package/dist/sync/credentials.js +1 -51
  96. package/dist/sync/files.d.ts +0 -1
  97. package/dist/sync/files.js +1 -71
  98. package/dist/sync/manifest.d.ts +0 -1
  99. package/dist/sync/manifest.js +1 -37
  100. package/dist/sync/repo-root.d.ts +0 -1
  101. package/dist/sync/repo-root.js +1 -24
  102. package/dist/sync/stitch-claude-md.d.ts +0 -1
  103. package/dist/sync/stitch-claude-md.js +8 -48
  104. package/dist/ui/colors.d.ts +0 -1
  105. package/dist/ui/colors.js +1 -28
  106. package/dist/ui/screens.d.ts +0 -1
  107. package/dist/ui/screens.js +5 -135
  108. package/package.json +8 -14
  109. package/plugin/.cursor-plugin/plugin.json +0 -2
  110. package/plugin/.mcp.json +1 -1
  111. package/plugin/LICENSE +15 -0
  112. package/plugin/README.md +3 -7
  113. package/plugin/gemini/gemini-extension.json +1 -1
  114. package/plugin/mcp.json +1 -1
  115. package/plugin/plugin.json +0 -2
  116. package/plugin/runtime/unfairly-intelligence.mjs +15 -0
  117. package/plugin/scripts/capture.cjs +30 -8
  118. package/plugin/skills/find-company-playbook/SKILL.md +1 -1
  119. package/dist/auth/browser-flow.d.ts.map +0 -1
  120. package/dist/auth/browser-flow.js.map +0 -1
  121. package/dist/cmd/connect.d.ts.map +0 -1
  122. package/dist/cmd/connect.js.map +0 -1
  123. package/dist/cmd/init.d.ts.map +0 -1
  124. package/dist/cmd/init.js.map +0 -1
  125. package/dist/cmd/invite.d.ts.map +0 -1
  126. package/dist/cmd/invite.js.map +0 -1
  127. package/dist/cmd/join.d.ts.map +0 -1
  128. package/dist/cmd/join.js.map +0 -1
  129. package/dist/cmd/login.d.ts.map +0 -1
  130. package/dist/cmd/login.js.map +0 -1
  131. package/dist/cmd/mcp.d.ts.map +0 -1
  132. package/dist/cmd/mcp.js.map +0 -1
  133. package/dist/cmd/pace.d.ts.map +0 -1
  134. package/dist/cmd/pace.js.map +0 -1
  135. package/dist/cmd/parse-share-input.d.ts.map +0 -1
  136. package/dist/cmd/parse-share-input.js.map +0 -1
  137. package/dist/cmd/pull.d.ts.map +0 -1
  138. package/dist/cmd/pull.js.map +0 -1
  139. package/dist/cmd/push.d.ts.map +0 -1
  140. package/dist/cmd/push.js.map +0 -1
  141. package/dist/cmd/resolve.d.ts.map +0 -1
  142. package/dist/cmd/resolve.js.map +0 -1
  143. package/dist/cmd/setup.d.ts.map +0 -1
  144. package/dist/cmd/setup.js.map +0 -1
  145. package/dist/cmd/status-card.d.ts.map +0 -1
  146. package/dist/cmd/status-card.js.map +0 -1
  147. package/dist/cmd/status.d.ts.map +0 -1
  148. package/dist/cmd/status.js.map +0 -1
  149. package/dist/cmd/watch.d.ts.map +0 -1
  150. package/dist/cmd/watch.js.map +0 -1
  151. package/dist/hosts/claude-code.d.ts.map +0 -1
  152. package/dist/hosts/claude-code.js.map +0 -1
  153. package/dist/hosts/claude-desktop.d.ts.map +0 -1
  154. package/dist/hosts/claude-desktop.js.map +0 -1
  155. package/dist/hosts/codex.d.ts.map +0 -1
  156. package/dist/hosts/codex.js.map +0 -1
  157. package/dist/hosts/shell-env.d.ts.map +0 -1
  158. package/dist/hosts/shell-env.js.map +0 -1
  159. package/dist/index.d.ts.map +0 -1
  160. package/dist/index.js.map +0 -1
  161. package/dist/lib/client.d.ts.map +0 -1
  162. package/dist/lib/client.js.map +0 -1
  163. package/dist/lib/events/emit.d.ts.map +0 -1
  164. package/dist/lib/events/emit.js.map +0 -1
  165. package/dist/lib/index.d.ts.map +0 -1
  166. package/dist/lib/index.js.map +0 -1
  167. package/dist/lib/transport.d.ts.map +0 -1
  168. package/dist/lib/transport.js.map +0 -1
  169. package/dist/lib/types/index.d.ts.map +0 -1
  170. package/dist/lib/types/index.js.map +0 -1
  171. package/dist/lib/vault/checkpoint.d.ts.map +0 -1
  172. package/dist/lib/vault/checkpoint.js.map +0 -1
  173. package/dist/lib/vault/read.d.ts.map +0 -1
  174. package/dist/lib/vault/read.js.map +0 -1
  175. package/dist/lib/vault/search.d.ts.map +0 -1
  176. package/dist/lib/vault/search.js.map +0 -1
  177. package/dist/pace/device.d.ts.map +0 -1
  178. package/dist/pace/device.js.map +0 -1
  179. package/dist/pace/identity.d.ts.map +0 -1
  180. package/dist/pace/identity.js.map +0 -1
  181. package/dist/pace/install.d.ts.map +0 -1
  182. package/dist/pace/install.js.map +0 -1
  183. package/dist/pace/local-evidence.d.ts.map +0 -1
  184. package/dist/pace/local-evidence.js.map +0 -1
  185. package/dist/pace/local-sessions.d.ts.map +0 -1
  186. package/dist/pace/local-sessions.js.map +0 -1
  187. package/dist/pace/managed-config.d.ts.map +0 -1
  188. package/dist/pace/managed-config.js.map +0 -1
  189. package/dist/pace/normalize.d.ts.map +0 -1
  190. package/dist/pace/normalize.js.map +0 -1
  191. package/dist/pace/repository.d.ts.map +0 -1
  192. package/dist/pace/repository.js.map +0 -1
  193. package/dist/pace/schema.d.ts.map +0 -1
  194. package/dist/pace/schema.js.map +0 -1
  195. package/dist/pace/session-summary.d.ts.map +0 -1
  196. package/dist/pace/session-summary.js.map +0 -1
  197. package/dist/pace/spool.d.ts.map +0 -1
  198. package/dist/pace/spool.js.map +0 -1
  199. package/dist/sync/api.d.ts.map +0 -1
  200. package/dist/sync/api.js.map +0 -1
  201. package/dist/sync/autoloader.d.ts.map +0 -1
  202. package/dist/sync/autoloader.js.map +0 -1
  203. package/dist/sync/conflict.d.ts.map +0 -1
  204. package/dist/sync/conflict.js.map +0 -1
  205. package/dist/sync/credentials.d.ts.map +0 -1
  206. package/dist/sync/credentials.js.map +0 -1
  207. package/dist/sync/files.d.ts.map +0 -1
  208. package/dist/sync/files.js.map +0 -1
  209. package/dist/sync/manifest.d.ts.map +0 -1
  210. package/dist/sync/manifest.js.map +0 -1
  211. package/dist/sync/repo-root.d.ts.map +0 -1
  212. package/dist/sync/repo-root.js.map +0 -1
  213. package/dist/sync/stitch-claude-md.d.ts.map +0 -1
  214. package/dist/sync/stitch-claude-md.js.map +0 -1
  215. package/dist/ui/colors.d.ts.map +0 -1
  216. package/dist/ui/colors.js.map +0 -1
  217. package/dist/ui/screens.d.ts.map +0 -1
  218. package/dist/ui/screens.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.8.4 — 2026-10-05
4
+
5
+ - **Proprietary license** — the package is now licensed under Unfairly's terms instead of MIT. It ships minified, without source maps, and no longer links to the source repository. Behavior is unchanged.
6
+
7
+ ## 0.8.3 — 2026-09-25
8
+
9
+ - **Connect in the same session** — after the person approves the machine in the browser, a detached poller claims the collector credential within seconds, so the session that showed the link starts reporting without a restart.
10
+ - **90-day backfill on first connect** — the first sync fetches the org's approved repositories and uploads the last 90 days of session summaries with their commits.
11
+ - **Members of several organizations** — the connect code survives the organization picker, so a member of more than one org can choose which one the machine reports to.
12
+
3
13
  ## 0.8.2 — 2026-09-24
4
14
 
5
15
  - **Unfairly Intelligence collector** — `unfairly setup` installs a metadata-only collector for Claude Code, Codex, Cursor, and Gemini CLI. At session boundaries it summarizes each session from the client's own local transcript: model, token counts by type, turns, tool calls and errors, approval denials, subagent use, the approved repository, the SHAs of the session's own commits, and which published skills or company playbooks it used. Prompts, responses, code, commands, paths, branch names, and commit messages never leave the machine; skills outside the published set are counted, not named.
package/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ Copyright (c) 2026 Unfairly AI. All rights reserved.
2
+
3
+ This software is proprietary and confidential. You may install and run it to
4
+ use Unfairly services under the terms at https://unfairly.ai. No other license
5
+ is granted to use, copy, modify, merge, publish, distribute, sublicense, or
6
+ sell copies of this software, in whole or in part, or to reverse engineer it,
7
+ except as expressly permitted in a separate written agreement with Unfairly AI.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
12
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
13
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
14
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
15
+ SOFTWARE.
package/README.md CHANGED
@@ -21,9 +21,11 @@ That's it. One command — auto-detects state and:
21
21
 
22
22
  Re-run any time inside the repo for a daily check-in card showing what your team's been up to.
23
23
 
24
+ For Unfairly Intelligence alone, most people install the plugin from their AI client's plugin screen instead (see `plugins/ai-pace/README.md`). `unfairly setup --org <org-id>` enrolls a machine into a specific organization, and `unfairly intelligence backfill --days 90` uploads summaries of past local sessions.
25
+
24
26
  ### Power-user commands
25
27
 
26
- `unfairly setup` (machine wiring), `unfairly intelligence install` (collector install/repair), `unfairly intelligence status`, `unfairly intelligence policy`, `unfairly intelligence pause`, `unfairly intelligence uninstall`, `unfairly init` (workspace bind only), `unfairly pull`, `unfairly push`, `unfairly status`, `unfairly watch`, `unfairly mcp`, `unfairly login`. The bare command above delegates to these — they're available when you want fine-grained control.
28
+ `unfairly setup` (machine wiring), `unfairly intelligence install` (collector install/repair), `unfairly intelligence status`, `unfairly intelligence backfill`, `unfairly intelligence policy`, `unfairly intelligence pause`, `unfairly intelligence uninstall`, `unfairly init` (workspace bind only), `unfairly pull`, `unfairly push`, `unfairly status`, `unfairly watch`, `unfairly mcp`, `unfairly login`. The bare command above delegates to these — they're available when you want fine-grained control.
27
29
 
28
30
  ## Commands
29
31
 
@@ -22,4 +22,3 @@ export declare function cliAuthUrl(apiUrl: string, input: {
22
22
  * verifies the state echo and resolves with the token.
23
23
  */
24
24
  export declare function browserAuthFlow(apiUrl: string, opts?: BrowserAuthOptions): Promise<string | null>;
25
- //# sourceMappingURL=browser-flow.d.ts.map
@@ -1,81 +1,5 @@
1
- import http from "node:http";
2
- import crypto from "node:crypto";
3
- import { spawn } from "node:child_process";
4
- const SUCCESS_HTML = `<!doctype html><html><head><meta charset="utf-8"><title>Unfairly CLI authorized</title><style>body{margin:0;background:#FAF5EB;font-family:system-ui;color:#1a1612;display:flex;align-items:center;justify-content:center;min-height:100vh}.card{background:#fff;border:3px solid #1a1612;border-radius:20px;box-shadow:6px 6px 0 #1a1612;padding:36px;max-width:420px;text-align:center}h1{margin:0 0 8px;font-size:28px}p{margin:0;color:rgba(26,22,18,.7)}</style></head><body><div class="card"><h1>Authorized.</h1><p>You can close this window and return to your terminal.</p></div></body></html>`;
5
- export function openBrowser(url) {
6
- const opener = process.platform === "darwin"
7
- ? "open"
8
- : process.platform === "win32"
9
- ? "cmd"
10
- : "xdg-open";
11
- const args = process.platform === "win32" ? ["/c", "start", "", url] : [url];
12
- try {
13
- spawn(opener, args, { stdio: "ignore", detached: true }).unref();
14
- }
15
- catch {
16
- // best-effort
17
- }
18
- }
19
- /** The /cli-auth page URL. An organization ID scopes the minted token to that org when the user is a member. */
20
- export function cliAuthUrl(apiUrl, input) {
21
- const url = new URL("/cli-auth", apiUrl);
22
- url.searchParams.set("cb", input.cb);
23
- url.searchParams.set("state", input.state);
24
- url.searchParams.set("name", input.tokenName);
25
- if (input.org && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(input.org))
26
- url.searchParams.set("org", input.org);
27
- return url;
28
- }
29
- /**
30
- * OAuth handshake via loopback HTTP server. Used by `unfairly setup`,
31
- * `unfairly login`, and `unfairly init`.
32
- *
33
- * Flow: pop a /cli-auth page in the user's browser with a one-time `state`
34
- * and a `cb=http://localhost:<port>/done` callback. The page mints a
35
- * `mcp_*` token and redirects the browser back to `cb`. Our local server
36
- * verifies the state echo and resolves with the token.
37
- */
38
- export async function browserAuthFlow(apiUrl, opts = {}) {
39
- const tokenName = opts.tokenName ?? "unfairly cli";
40
- const timeoutMs = opts.timeoutMs ?? 5 * 60_000;
41
- const state = crypto.randomBytes(16).toString("base64url");
42
- return new Promise((resolve) => {
43
- let resolved = false;
44
- const cleanup = (val) => {
45
- if (resolved)
46
- return;
47
- resolved = true;
48
- setTimeout(() => server.close(), 500);
49
- resolve(val);
50
- };
51
- const server = http.createServer((req, res) => {
52
- const url = new URL(req.url ?? "/", "http://localhost");
53
- if (url.pathname !== "/done") {
54
- res.writeHead(404).end();
55
- return;
56
- }
57
- const echoState = url.searchParams.get("state") ?? "";
58
- const token = url.searchParams.get("token") ?? "";
59
- if (echoState !== state || !token.startsWith("mcp_")) {
60
- res.writeHead(400).end("Auth failed");
61
- cleanup(null);
62
- return;
63
- }
64
- res
65
- .writeHead(200, { "Content-Type": "text/html; charset=utf-8" })
66
- .end(SUCCESS_HTML);
67
- cleanup(token);
68
- });
69
- const timeout = setTimeout(() => cleanup(null), timeoutMs);
70
- server.on("close", () => clearTimeout(timeout));
71
- server.listen(0, "127.0.0.1", () => {
72
- const addr = server.address();
73
- const port = typeof addr === "object" && addr ? addr.port : 0;
74
- const cb = `http://localhost:${port}/done`;
75
- const authUrl = cliAuthUrl(apiUrl, { cb, state, tokenName, org: opts.org ?? process.env.UNFAIRLY_ORG });
76
- console.error(`\nOpening browser to authorize:\n ${authUrl.toString()}\n(if it doesn't open, click the link above)\n`);
77
- openBrowser(authUrl.toString());
78
- });
79
- });
80
- }
81
- //# sourceMappingURL=browser-flow.js.map
1
+ import f from"node:http";import g from"node:crypto";import{spawn as y}from"node:child_process";const w='<!doctype html><html><head><meta charset="utf-8"><title>Unfairly CLI authorized</title><style>body{margin:0;background:#FAF5EB;font-family:system-ui;color:#1a1612;display:flex;align-items:center;justify-content:center;min-height:100vh}.card{background:#fff;border:3px solid #1a1612;border-radius:20px;box-shadow:6px 6px 0 #1a1612;padding:36px;max-width:420px;text-align:center}h1{margin:0 0 8px;font-size:28px}p{margin:0;color:rgba(26,22,18,.7)}</style></head><body><div class="card"><h1>Authorized.</h1><p>You can close this window and return to your terminal.</p></div></body></html>';function b(r){const t=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",e=process.platform==="win32"?["/c","start","",r]:[r];try{y(t,e,{stdio:"ignore",detached:!0}).unref()}catch{}}function x(r,t){const e=new URL("/cli-auth",r);return e.searchParams.set("cb",t.cb),e.searchParams.set("state",t.state),e.searchParams.set("name",t.tokenName),t.org&&/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(t.org)&&e.searchParams.set("org",t.org),e}async function P(r,t={}){const e=t.tokenName??"unfairly cli",h=t.timeoutMs??5*6e4,l=g.randomBytes(16).toString("base64url");return new Promise(p=>{let d=!1;const i=o=>{d||(d=!0,setTimeout(()=>n.close(),500),p(o))},n=f.createServer((o,s)=>{const a=new URL(o.url??"/","http://localhost");if(a.pathname!=="/done"){s.writeHead(404).end();return}const c=a.searchParams.get("state")??"",m=a.searchParams.get("token")??"";if(c!==l||!m.startsWith("mcp_")){s.writeHead(400).end("Auth failed"),i(null);return}s.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}).end(w),i(m)}),u=setTimeout(()=>i(null),h);n.on("close",()=>clearTimeout(u)),n.listen(0,"127.0.0.1",()=>{const o=n.address(),a=`http://localhost:${typeof o=="object"&&o?o.port:0}/done`,c=x(r,{cb:a,state:l,tokenName:e,org:t.org??process.env.UNFAIRLY_ORG});console.error(`
2
+ Opening browser to authorize:
3
+ ${c.toString()}
4
+ (if it doesn't open, click the link above)
5
+ `),b(c.toString())})})}export{P as browserAuthFlow,x as cliAuthUrl,b as openBrowser};
@@ -58,4 +58,3 @@ export declare const connectCommand: {
58
58
  handler: (args: ConnectArgs) => Promise<void>;
59
59
  };
60
60
  export {};
61
- //# sourceMappingURL=connect.d.ts.map
@@ -1,164 +1 @@
1
- import { parseShareInput } from "./parse-share-input.js";
2
- import { addScopedClaudeDesktopEntry, } from "../hosts/claude-desktop.js";
3
- import { addScopedClaudeCodeEntry } from "../hosts/claude-code.js";
4
- import { addScopedCodexEntry, } from "../hosts/codex.js";
5
- const API_DEFAULT = "https://app.unfairly.ai";
6
- /**
7
- * Map a mint endpoint error code to a user-facing message.
8
- */
9
- function describeMintError(status, code) {
10
- if (status === 404 || code === "not_found") {
11
- return "share link not found — double-check the URL or ask the sender to issue a new one.";
12
- }
13
- if (status === 410 || code === "revoked_or_expired") {
14
- return "share link expired or was revoked — ask the sender for a fresh one.";
15
- }
16
- if (status === 429 || code === "rate_limited") {
17
- return "rate limited (10 mints / hour per link) — try again in an hour.";
18
- }
19
- if (status === 400 || code === "no_room") {
20
- return "invalid share link — it isn't bound to a vault.";
21
- }
22
- return `server error while minting (${status} ${code}).`;
23
- }
24
- /**
25
- * Pure-ish implementation. Tests inject `deps` to drive without hitting
26
- * the network or touching real config files.
27
- */
28
- export async function runConnect(args, deps) {
29
- let parsed;
30
- try {
31
- parsed = parseShareInput(args.urlOrId);
32
- }
33
- catch (err) {
34
- deps.errLog(`✗ ${err.message}`);
35
- return { ok: false, exitCode: 1 };
36
- }
37
- const apiOrigin = args.api ?? parsed.origin ?? API_DEFAULT;
38
- const mintUrl = `${apiOrigin.replace(/\/$/, "")}/api/share-links/${parsed.shareId}/mint-token`;
39
- const body = {};
40
- if (args.as)
41
- body.email = args.as;
42
- if (args.label)
43
- body.label = args.label;
44
- deps.log("✦ Minting a 24-hour vault token…");
45
- let res;
46
- try {
47
- res = await deps.fetch(mintUrl, {
48
- method: "POST",
49
- headers: { "Content-Type": "application/json" },
50
- body: JSON.stringify(body),
51
- });
52
- }
53
- catch (err) {
54
- deps.errLog(`✗ network error reaching ${apiOrigin}: ${err.message}`);
55
- return { ok: false, exitCode: 1, shareId: parsed.shareId };
56
- }
57
- if (!res.ok) {
58
- let parsedErr = { error: "unknown" };
59
- try {
60
- parsedErr = (await res.json());
61
- }
62
- catch {
63
- // body wasn't JSON — fall through with default
64
- }
65
- const message = describeMintError(res.status, parsedErr.error ?? "unknown");
66
- deps.errLog(`✗ ${message}`);
67
- return {
68
- ok: false,
69
- exitCode: 1,
70
- shareId: parsed.shareId,
71
- errorCode: parsedErr.error,
72
- };
73
- }
74
- let mint;
75
- try {
76
- mint = (await res.json());
77
- }
78
- catch (err) {
79
- deps.errLog(`✗ mint endpoint returned non-JSON: ${err.message}`);
80
- return { ok: false, exitCode: 1, shareId: parsed.shareId };
81
- }
82
- if (!mint.token || !mint.mcp_url) {
83
- deps.errLog("✗ mint endpoint response missing token or mcp_url");
84
- return { ok: false, exitCode: 1, shareId: parsed.shareId };
85
- }
86
- const input = {
87
- orgSlug: mint.org_slug,
88
- roomSlug: mint.room_slug,
89
- shareLinkId: parsed.shareId,
90
- token: mint.token,
91
- mcpUrl: mint.mcp_url,
92
- };
93
- const [claudeDesktop, claudeCode, codex] = await Promise.all([
94
- deps.addClaudeDesktop(input),
95
- deps.addClaudeCode(input),
96
- deps.addCodex(input),
97
- ]);
98
- // Per-host success line.
99
- const reportHost = (name, result) => {
100
- if (result.status === "configured") {
101
- const verb = "replaced" in result && result.replaced ? "Updated" : "Wired";
102
- deps.log(`✓ ${verb} ${name} · ${result.key}`);
103
- }
104
- else if (result.status === "not-installed") {
105
- deps.log(` (${name} not installed — skipped)`);
106
- }
107
- else {
108
- deps.errLog(`✗ ${name}: ${result.message ?? "unknown error"}`);
109
- }
110
- };
111
- reportHost("Claude Desktop", claudeDesktop);
112
- reportHost("Claude Code", claudeCode);
113
- reportHost("Codex", codex);
114
- deps.log("");
115
- deps.log("→ Open your AI host. Ask: \"what's in this vault?\"");
116
- if (mint.expires_at) {
117
- deps.log(` Token expires at ${mint.expires_at} (≤24h).`);
118
- }
119
- else {
120
- deps.log(" Token expires in 24h.");
121
- }
122
- return {
123
- ok: true,
124
- exitCode: 0,
125
- shareId: parsed.shareId,
126
- hosts: { claudeDesktop, claudeCode, codex },
127
- mint,
128
- };
129
- }
130
- export const connectCommand = {
131
- command: "connect <urlOrId>",
132
- describe: "Connect to a shared vault via share link — mints a 24h token, wires all hosts",
133
- builder: (yargs) => yargs
134
- .positional("urlOrId", {
135
- type: "string",
136
- demandOption: true,
137
- describe: "Share link URL (https://app.unfairly.ai/s/<uuid>), short form (s/<uuid>), or bare UUID",
138
- })
139
- .option("as", {
140
- type: "string",
141
- describe: "Email to attribute the token to (audit only)",
142
- })
143
- .option("label", {
144
- type: "string",
145
- describe: "Human label for the audit log (≤100 chars)",
146
- })
147
- .option("api", {
148
- type: "string",
149
- describe: "Override the API origin (defaults to the URL's origin or app.unfairly.ai)",
150
- }),
151
- handler: async (args) => {
152
- const outcome = await runConnect(args, {
153
- fetch: globalThis.fetch.bind(globalThis),
154
- addClaudeDesktop: addScopedClaudeDesktopEntry,
155
- addClaudeCode: addScopedClaudeCodeEntry,
156
- addCodex: addScopedCodexEntry,
157
- log: (line) => console.log(line),
158
- errLog: (line) => console.error(line),
159
- });
160
- if (!outcome.ok)
161
- process.exit(outcome.exitCode);
162
- },
163
- };
164
- //# sourceMappingURL=connect.js.map
1
+ import{parseShareInput as g}from"./parse-share-input.js";import{addScopedClaudeDesktopEntry as f}from"../hosts/claude-desktop.js";import{addScopedClaudeCodeEntry as C}from"../hosts/claude-code.js";import{addScopedCodexEntry as y}from"../hosts/codex.js";const b="https://app.unfairly.ai";function x(r,e){return r===404||e==="not_found"?"share link not found \u2014 double-check the URL or ask the sender to issue a new one.":r===410||e==="revoked_or_expired"?"share link expired or was revoked \u2014 ask the sender for a fresh one.":r===429||e==="rate_limited"?"rate limited (10 mints / hour per link) \u2014 try again in an hour.":r===400||e==="no_room"?"invalid share link \u2014 it isn't bound to a vault.":`server error while minting (${r} ${e}).`}async function I(r,e){let o;try{o=g(r.urlOrId)}catch(t){return e.errLog(`\u2717 ${t.message}`),{ok:!1,exitCode:1}}const u=r.api??o.origin??b,k=`${u.replace(/\/$/,"")}/api/share-links/${o.shareId}/mint-token`,s={};r.as&&(s.email=r.as),r.label&&(s.label=r.label),e.log("\u2726 Minting a 24-hour vault token\u2026");let a;try{a=await e.fetch(k,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)})}catch(t){return e.errLog(`\u2717 network error reaching ${u}: ${t.message}`),{ok:!1,exitCode:1,shareId:o.shareId}}if(!a.ok){let t={error:"unknown"};try{t=await a.json()}catch{}const i=x(a.status,t.error??"unknown");return e.errLog(`\u2717 ${i}`),{ok:!1,exitCode:1,shareId:o.shareId,errorCode:t.error}}let n;try{n=await a.json()}catch(t){return e.errLog(`\u2717 mint endpoint returned non-JSON: ${t.message}`),{ok:!1,exitCode:1,shareId:o.shareId}}if(!n.token||!n.mcp_url)return e.errLog("\u2717 mint endpoint response missing token or mcp_url"),{ok:!1,exitCode:1,shareId:o.shareId};const d={orgSlug:n.org_slug,roomSlug:n.room_slug,shareLinkId:o.shareId,token:n.token,mcpUrl:n.mcp_url},[h,c,p]=await Promise.all([e.addClaudeDesktop(d),e.addClaudeCode(d),e.addCodex(d)]),l=(t,i)=>{if(i.status==="configured"){const m="replaced"in i&&i.replaced?"Updated":"Wired";e.log(`\u2713 ${m} ${t} \xB7 ${i.key}`)}else i.status==="not-installed"?e.log(` (${t} not installed \u2014 skipped)`):e.errLog(`\u2717 ${t}: ${i.message??"unknown error"}`)};return l("Claude Desktop",h),l("Claude Code",c),l("Codex",p),e.log(""),e.log(`\u2192 Open your AI host. Ask: "what's in this vault?"`),n.expires_at?e.log(` Token expires at ${n.expires_at} (\u226424h).`):e.log(" Token expires in 24h."),{ok:!0,exitCode:0,shareId:o.shareId,hosts:{claudeDesktop:h,claudeCode:c,codex:p},mint:n}}const v={command:"connect <urlOrId>",describe:"Connect to a shared vault via share link \u2014 mints a 24h token, wires all hosts",builder:r=>r.positional("urlOrId",{type:"string",demandOption:!0,describe:"Share link URL (https://app.unfairly.ai/s/<uuid>), short form (s/<uuid>), or bare UUID"}).option("as",{type:"string",describe:"Email to attribute the token to (audit only)"}).option("label",{type:"string",describe:"Human label for the audit log (\u2264100 chars)"}).option("api",{type:"string",describe:"Override the API origin (defaults to the URL's origin or app.unfairly.ai)"}),handler:async r=>{const e=await I(r,{fetch:globalThis.fetch.bind(globalThis),addClaudeDesktop:f,addClaudeCode:C,addCodex:y,log:o=>console.log(o),errLog:o=>console.error(o)});e.ok||process.exit(e.exitCode)}};export{v as connectCommand,I as runConnect};
@@ -6,4 +6,3 @@ export type InitOptions = {
6
6
  assumeAuthed?: boolean;
7
7
  };
8
8
  export declare function runInit(opts?: InitOptions): Promise<void>;
9
- //# sourceMappingURL=init.d.ts.map
package/dist/cmd/init.js CHANGED
@@ -1,138 +1,2 @@
1
- import { promises as fs } from "node:fs";
2
- import path from "node:path";
3
- import readline from "node:readline/promises";
4
- import { stdin as input, stdout as output } from "node:process";
5
- import { SyncClient } from "../sync/api.js";
6
- import { emptyManifest, writeManifest } from "../sync/manifest.js";
7
- import { getToken, setToken } from "../sync/credentials.js";
8
- import { browserAuthFlow } from "../auth/browser-flow.js";
9
- import { runPull } from "./pull.js";
10
- import { findRepoRoot } from "../sync/repo-root.js";
11
- import { stitchClaudeMd } from "../sync/stitch-claude-md.js";
12
- import { banner, stepHeader, result, divider, defaultOpts } from "../ui/screens.js";
13
- const DEFAULT_API = "https://app.unfairly.ai";
14
- function isTty() {
15
- return Boolean(process.stdin.isTTY);
16
- }
17
- export async function runInit(opts = {}) {
18
- const cwd = process.cwd();
19
- const target = path.join(cwd, ".unfairly");
20
- const apiUrl = process.env.UNFAIRLY_API_URL ?? DEFAULT_API;
21
- const ui = defaultOpts();
22
- const write = (s) => process.stderr.write(`${s}\n`);
23
- if (!opts.assumeAuthed) {
24
- write(banner(ui));
25
- write("");
26
- }
27
- // Confirm overwrite if .unfairly/ already exists
28
- try {
29
- await fs.access(target);
30
- if (!opts.yes) {
31
- if (!isTty()) {
32
- write(result("err", ".unfairly/ already exists — re-run with --yes to overwrite (non-TTY).", ui));
33
- process.exit(1);
34
- }
35
- const rl = readline.createInterface({ input, output });
36
- const ans = await rl.question(`.unfairly/ already exists. Re-initialize? [y/N] `);
37
- rl.close();
38
- if (ans.trim().toLowerCase() !== "y") {
39
- write(result("skip", "aborted", ui));
40
- return;
41
- }
42
- }
43
- }
44
- catch {
45
- // didn't exist; fine
46
- }
47
- // Resolve token (flag → env → keychain → browser → paste)
48
- let token = opts.token ?? process.env.UNFAIRLY_TOKEN ?? (await getToken());
49
- if (!token) {
50
- if (!isTty()) {
51
- write(result("err", "No token. Pass --token or set UNFAIRLY_TOKEN (non-TTY).", ui));
52
- process.exit(1);
53
- }
54
- if (!opts.noBrowser) {
55
- const fromBrowser = await browserAuthFlow(apiUrl);
56
- if (fromBrowser)
57
- token = fromBrowser;
58
- }
59
- if (!token) {
60
- const rl = readline.createInterface({ input, output });
61
- token = (await rl.question("Paste mcp_* token: ")).trim();
62
- rl.close();
63
- }
64
- }
65
- if (!token || !token.startsWith("mcp_")) {
66
- write(result("err", "Token must start with mcp_", ui));
67
- process.exit(1);
68
- }
69
- await setToken(token);
70
- // Verify + list vaults
71
- const client = new SyncClient(apiUrl, token);
72
- write(stepHeader(1, 3, "VAULT INVENTORY", ui));
73
- let status;
74
- try {
75
- status = await client.status();
76
- }
77
- catch (err) {
78
- write(result("err", `failed to reach ${apiUrl}/api/sync/status — ${err.message}`, ui));
79
- process.exit(1);
80
- }
81
- if (status.vaults.length === 0) {
82
- write(result("err", "no accessible vaults. Ask an admin to grant you access.", ui));
83
- process.exit(1);
84
- }
85
- for (const v of status.vaults.slice(0, 6)) {
86
- write(result("ok", `${v.name.padEnd(20)} · ${v.doc_count} docs${v.track_in_git ? "" : " (gitignored)"}`, ui));
87
- }
88
- if (status.vaults.length > 6) {
89
- const remaining = status.vaults.length - 6;
90
- const totalDocs = status.vaults.reduce((s, v) => s + v.doc_count, 0);
91
- write(result("skip", `… ${remaining} more vaults · ${totalDocs} docs total`, ui));
92
- }
93
- write("");
94
- // Seed manifest + pull
95
- write(stepHeader(2, 3, "PULL", ui));
96
- await fs.mkdir(target, { recursive: true });
97
- const manifest = emptyManifest(apiUrl);
98
- for (const v of status.vaults) {
99
- manifest.vaults[v.slug] = {
100
- id: v.id,
101
- slug: v.slug,
102
- name: v.name,
103
- track_in_git: v.track_in_git,
104
- last_pulled_at: null,
105
- last_pushed_at: null,
106
- docs: {},
107
- };
108
- }
109
- await writeManifest(cwd, manifest);
110
- await runPull(undefined);
111
- write(result("ok", "wrote .unfairly/CLAUDE.md (auto-loader for Claude Code)", ui));
112
- write("");
113
- // Stitch repo's root CLAUDE.md
114
- write(stepHeader(3, 3, "STITCH", ui));
115
- const repoRoot = await findRepoRoot(cwd);
116
- if (!repoRoot) {
117
- write(result("skip", "not in a git repo — skipping CLAUDE.md stitch", ui));
118
- }
119
- else {
120
- const stitch = await stitchClaudeMd(repoRoot);
121
- if (stitch.action === "created") {
122
- write(result("ok", `created ${stitch.path} with @.unfairly/CLAUDE.md`, ui));
123
- }
124
- else if (stitch.action === "appended") {
125
- write(result("ok", `appended @.unfairly/CLAUDE.md to ${stitch.path}`, ui));
126
- }
127
- else if (stitch.action === "noop") {
128
- write(result("skip", `${stitch.path} already references the autoloader`, ui));
129
- }
130
- else if (stitch.action === "error") {
131
- write(result("warn", `couldn't stitch ${stitch.path} — ${stitch.message}`, ui));
132
- }
133
- }
134
- write("");
135
- write(divider(ui));
136
- write("");
137
- }
138
- //# sourceMappingURL=init.js.map
1
+ import{promises as m}from"node:fs";import v from"node:path";import w from"node:readline/promises";import{stdin as h,stdout as k}from"node:process";import{SyncClient as A}from"../sync/api.js";import{emptyManifest as L,writeManifest as $}from"../sync/manifest.js";import{getToken as U,setToken as C}from"../sync/credentials.js";import{browserAuthFlow as I}from"../auth/browser-flow.js";import{runPull as E}from"./pull.js";import{findRepoRoot as N}from"../sync/repo-root.js";import{stitchClaudeMd as R}from"../sync/stitch-claude-md.js";import{banner as x,stepHeader as u,result as o,divider as Y,defaultOpts as D}from"../ui/screens.js";const P="https://app.unfairly.ai";function y(){return!!process.stdin.isTTY}async function W(a={}){const c=process.cwd(),p=v.join(c,".unfairly"),n=process.env.UNFAIRLY_API_URL??P,s=D(),e=t=>process.stderr.write(`${t}
2
+ `);a.assumeAuthed||(e(x(s)),e(""));try{if(await m.access(p),!a.yes){y()||(e(o("err",".unfairly/ already exists \u2014 re-run with --yes to overwrite (non-TTY).",s)),process.exit(1));const t=w.createInterface({input:h,output:k}),l=await t.question(".unfairly/ already exists. Re-initialize? [y/N] ");if(t.close(),l.trim().toLowerCase()!=="y"){e(o("skip","aborted",s));return}}}catch{}let r=a.token??process.env.UNFAIRLY_TOKEN??await U();if(!r){if(y()||(e(o("err","No token. Pass --token or set UNFAIRLY_TOKEN (non-TTY).",s)),process.exit(1)),!a.noBrowser){const t=await I(n);t&&(r=t)}if(!r){const t=w.createInterface({input:h,output:k});r=(await t.question("Paste mcp_* token: ")).trim(),t.close()}}(!r||!r.startsWith("mcp_"))&&(e(o("err","Token must start with mcp_",s)),process.exit(1)),await C(r);const _=new A(n,r);e(u(1,3,"VAULT INVENTORY",s));let i;try{i=await _.status()}catch(t){e(o("err",`failed to reach ${n}/api/sync/status \u2014 ${t.message}`,s)),process.exit(1)}i.vaults.length===0&&(e(o("err","no accessible vaults. Ask an admin to grant you access.",s)),process.exit(1));for(const t of i.vaults.slice(0,6))e(o("ok",`${t.name.padEnd(20)} \xB7 ${t.doc_count} docs${t.track_in_git?"":" (gitignored)"}`,s));if(i.vaults.length>6){const t=i.vaults.length-6,l=i.vaults.reduce((g,T)=>g+T.doc_count,0);e(o("skip",`\u2026 ${t} more vaults \xB7 ${l} docs total`,s))}e(""),e(u(2,3,"PULL",s)),await m.mkdir(p,{recursive:!0});const f=L(n);for(const t of i.vaults)f.vaults[t.slug]={id:t.id,slug:t.slug,name:t.name,track_in_git:t.track_in_git,last_pulled_at:null,last_pushed_at:null,docs:{}};await $(c,f),await E(void 0),e(o("ok","wrote .unfairly/CLAUDE.md (auto-loader for Claude Code)",s)),e(""),e(u(3,3,"STITCH",s));const d=await N(c);if(!d)e(o("skip","not in a git repo \u2014 skipping CLAUDE.md stitch",s));else{const t=await R(d);t.action==="created"?e(o("ok",`created ${t.path} with @.unfairly/CLAUDE.md`,s)):t.action==="appended"?e(o("ok",`appended @.unfairly/CLAUDE.md to ${t.path}`,s)):t.action==="noop"?e(o("skip",`${t.path} already references the autoloader`,s)):t.action==="error"&&e(o("warn",`couldn't stitch ${t.path} \u2014 ${t.message}`,s))}e(""),e(Y(s)),e("")}export{W as runInit};
@@ -23,4 +23,3 @@ export declare const inviteCommand: {
23
23
  handler: (args: InviteArgs) => Promise<void>;
24
24
  };
25
25
  export {};
26
- //# sourceMappingURL=invite.d.ts.map
@@ -1,73 +1,4 @@
1
- import { getToken } from "../sync/credentials.js";
2
- const API_DEFAULT = "https://app.unfairly.ai";
3
- export const inviteCommand = {
4
- command: "invite",
5
- describe: "Generate a persona-tagged invite link for a teammate",
6
- builder: (yargs) => yargs
7
- .option("email", {
8
- type: "string",
9
- demandOption: true,
10
- describe: "Email of the person you're inviting",
11
- })
12
- .option("persona-surface", {
13
- type: "string",
14
- demandOption: true,
15
- choices: ["builder-terminal", "player-web"],
16
- describe: "Onboarding role: builder-terminal = Champion, player-web = Player",
17
- })
18
- .option("persona-workflow", {
19
- type: "string",
20
- choices: [
21
- "strategy",
22
- "synthesis",
23
- "clinical-operations",
24
- "credentialing",
25
- "technical",
26
- "recruiting",
27
- ],
28
- describe: "What workflow they own",
29
- })
30
- .option("org", {
31
- type: "string",
32
- describe: "Org slug or id (required for CLI; web infers from cookie)",
33
- })
34
- .option("api", {
35
- type: "string",
36
- default: API_DEFAULT,
37
- describe: "API origin",
38
- }),
39
- handler: async (args) => {
40
- const token = await getToken();
41
- if (!token) {
42
- console.error("Not signed in. Run `unfairly login` first, then re-run `unfairly invite`.");
43
- process.exit(1);
44
- }
45
- const res = await fetch(`${args.api}/api/onboard/invite`, {
46
- method: "POST",
47
- headers: {
48
- "Content-Type": "application/json",
49
- Authorization: `Bearer ${token}`,
50
- },
51
- body: JSON.stringify({
52
- email: args.email,
53
- persona_surface: args["persona-surface"],
54
- persona_workflow: args["persona-workflow"],
55
- org_slug: args.org,
56
- }),
57
- });
58
- if (!res.ok) {
59
- const err = await res.text();
60
- console.error(`Failed to create invite: ${res.status} ${err}`);
61
- process.exit(1);
62
- }
63
- const data = await res.json();
64
- console.log(`\n✦ Invite ready for ${data.target_email}`);
65
- console.log(` Surface: ${data.persona_surface}`);
66
- if (data.persona_workflow) {
67
- console.log(` Workflow: ${data.persona_workflow}`);
68
- }
69
- console.log(`\n ${data.url}\n`);
70
- console.log(`Send that to them. They'll paste-run \`npx unfairly join\` from there.\n`);
71
- },
72
- };
73
- //# sourceMappingURL=invite.js.map
1
+ import{getToken as t}from"../sync/credentials.js";const a="https://app.unfairly.ai",l={command:"invite",describe:"Generate a persona-tagged invite link for a teammate",builder:e=>e.option("email",{type:"string",demandOption:!0,describe:"Email of the person you're inviting"}).option("persona-surface",{type:"string",demandOption:!0,choices:["builder-terminal","player-web"],describe:"Onboarding role: builder-terminal = Champion, player-web = Player"}).option("persona-workflow",{type:"string",choices:["strategy","synthesis","clinical-operations","credentialing","technical","recruiting"],describe:"What workflow they own"}).option("org",{type:"string",describe:"Org slug or id (required for CLI; web infers from cookie)"}).option("api",{type:"string",default:a,describe:"API origin"}),handler:async e=>{const n=await t();n||(console.error("Not signed in. Run `unfairly login` first, then re-run `unfairly invite`."),process.exit(1));const r=await fetch(`${e.api}/api/onboard/invite`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`},body:JSON.stringify({email:e.email,persona_surface:e["persona-surface"],persona_workflow:e["persona-workflow"],org_slug:e.org})});if(!r.ok){const i=await r.text();console.error(`Failed to create invite: ${r.status} ${i}`),process.exit(1)}const o=await r.json();console.log(`
2
+ \u2726 Invite ready for ${o.target_email}`),console.log(` Surface: ${o.persona_surface}`),o.persona_workflow&&console.log(` Workflow: ${o.persona_workflow}`),console.log(`
3
+ ${o.url}
4
+ `),console.log("Send that to them. They'll paste-run `npx unfairly join` from there.\n")}};export{l as inviteCommand};
@@ -17,4 +17,3 @@ export declare const joinCommand: {
17
17
  handler: (args: JoinArgs) => Promise<void>;
18
18
  };
19
19
  export {};
20
- //# sourceMappingURL=join.d.ts.map