unfairly 0.6.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.8.0 — 2026-05-15
4
+
5
+ - **`unfairly connect <urlOrId>`** — wire a shared vault from a share link in one command, no browser OAuth, no signup. POSTs the link to the new `/api/share-links/<id>/mint-token` endpoint (Phase B), receives a ≤24h read-only token, and writes it to Claude Desktop, Claude Code, and Codex as scoped MCP entries keyed by `unfairly-<org>-<room>`. Accepts the full URL, `s/<uuid>` short form, or a bare UUID. `--as <email>` and `--label <text>` flow through to the audit log. Re-connecting the same share link is idempotent — strips the old entry and writes a fresh token at the same key. Hosts that aren't installed are skipped, not errored.
6
+ - **Multi-entry host writers** — new `addScopedClaudeDesktopEntry`, `addScopedClaudeCodeEntry`, and `addScopedCodexEntry` write per-share_link entries alongside the canonical `unfairly` entry. JSON-host entries carry `_meta.shareLinkId` for idempotent rotation; Codex blocks use a `# share_link_id = "<id>"` comment line as the equivalent tag. Numbered-slot collision handling reuses gaps (e.g. with `unfairly-org-hq` + `unfairly-org-hq-3` taken, the next new entry lands at `unfairly-org-hq-2`). Scoped Codex blocks inline the literal bearer_token — these tokens are short-lived one-offs, env-var indirection isn't worth the setup friction.
7
+ - **`parseShareInput`** — pure parser exported from `cmd/parse-share-input.ts`. Handles `https://app.unfairly.ai/s/<uuid>`, `https://preview.../s/<uuid>` (preserves origin so we mint against the same host), `s/<uuid>`, and bare UUIDs. Throws friendly errors on junk input.
8
+
3
9
  ## 0.6.1 — 2026-05-14
4
10
 
5
11
  - **Fix(Claude Code wiring)** — `unfairly setup` now writes the user-scope `unfairly` entry directly to `~/.claude.json` instead of shelling out to `claude mcp add --header=…`. The shell-out form previously omitted the bearer entirely (`claude mcp list` showed "Needs authentication"), and even when fixed would have placed the raw token in process argv for the lifetime of the subprocess — visible to same-user processes via `ps aux` / `/proc/<pid>/cmdline`. Direct JSON edit keeps the token off the process table, same threat model as the Claude Desktop wiring. Strips any stale project-scope `projects[<cwd>].mcpServers.unfairly` left over from earlier local-scope installs so they don't shadow the user-scope entry.
@@ -1,3 +1,4 @@
1
+ export declare function openBrowser(url: string): void;
1
2
  export type BrowserAuthOptions = {
2
3
  tokenName?: string;
3
4
  timeoutMs?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"browser-flow.d.ts","sourceRoot":"","sources":["../../src/auth/browser-flow.ts"],"names":[],"mappings":"AAsBA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,kBAAuB,GAC5B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA+CxB"}
1
+ {"version":3,"file":"browser-flow.d.ts","sourceRoot":"","sources":["../../src/auth/browser-flow.ts"],"names":[],"mappings":"AAMA,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAc7C;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,kBAAuB,GAC5B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA+CxB"}
@@ -2,7 +2,7 @@ import http from "node:http";
2
2
  import crypto from "node:crypto";
3
3
  import { spawn } from "node:child_process";
4
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
- function openBrowser(url) {
5
+ export function openBrowser(url) {
6
6
  const opener = process.platform === "darwin"
7
7
  ? "open"
8
8
  : process.platform === "win32"
@@ -1 +1 @@
1
- {"version":3,"file":"browser-flow.js","sourceRoot":"","sources":["../../src/auth/browser-flow.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"browser-flow.js","sourceRoot":"","sources":["../../src/auth/browser-flow.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ import type { Argv } from "yargs";
2
+ import { type AddScopedEntryInput, type AddScopedEntryResult } from "../hosts/claude-desktop.js";
3
+ import { type AddScopedCodexResult } from "../hosts/codex.js";
4
+ type ConnectArgs = {
5
+ urlOrId: string;
6
+ as?: string;
7
+ label?: string;
8
+ api?: string;
9
+ };
10
+ export type MintResponseOk = {
11
+ token: string;
12
+ mcp_url: string;
13
+ org_slug: string | null;
14
+ room_slug: string | null;
15
+ expires_at: string | null;
16
+ };
17
+ export type MintResponseErr = {
18
+ error: string;
19
+ message?: string;
20
+ };
21
+ export type ConnectDeps = {
22
+ fetch: typeof fetch;
23
+ addClaudeDesktop: (input: AddScopedEntryInput) => Promise<AddScopedEntryResult>;
24
+ addClaudeCode: (input: AddScopedEntryInput) => Promise<AddScopedEntryResult>;
25
+ addCodex: (input: AddScopedEntryInput) => Promise<AddScopedCodexResult>;
26
+ log: (line: string) => void;
27
+ errLog: (line: string) => void;
28
+ };
29
+ export type ConnectOutcome = {
30
+ ok: boolean;
31
+ exitCode: number;
32
+ shareId?: string;
33
+ hosts?: {
34
+ claudeDesktop: AddScopedEntryResult;
35
+ claudeCode: AddScopedEntryResult;
36
+ codex: AddScopedCodexResult;
37
+ };
38
+ mint?: MintResponseOk;
39
+ errorCode?: string;
40
+ };
41
+ /**
42
+ * Pure-ish implementation. Tests inject `deps` to drive without hitting
43
+ * the network or touching real config files.
44
+ */
45
+ export declare function runConnect(args: ConnectArgs, deps: ConnectDeps): Promise<ConnectOutcome>;
46
+ export declare const connectCommand: {
47
+ command: string;
48
+ describe: string;
49
+ builder: (yargs: Argv) => Argv<{
50
+ urlOrId: string;
51
+ } & {
52
+ as: string | undefined;
53
+ } & {
54
+ label: string | undefined;
55
+ } & {
56
+ api: string | undefined;
57
+ }>;
58
+ handler: (args: ConnectArgs) => Promise<void>;
59
+ };
60
+ export {};
61
+ //# sourceMappingURL=connect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../../src/cmd/connect.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAElC,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EAC1B,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,mBAAmB,CAAC;AAI3B,KAAK,WAAW,GAAG;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB,gBAAgB,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAChF,aAAa,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAC7E,QAAQ,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACxE,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE;QACN,aAAa,EAAE,oBAAoB,CAAC;QACpC,UAAU,EAAE,oBAAoB,CAAC;QACjC,KAAK,EAAE,oBAAoB,CAAC;KAC7B,CAAC;IACF,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAqBF;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,WAAW,EACjB,IAAI,EAAE,WAAW,GAChB,OAAO,CAAC,cAAc,CAAC,CA4GzB;AAED,eAAO,MAAM,cAAc;;;qBAGR,IAAI;;;;;;;;;oBAmBC,WAAW;CAWlC,CAAC"}
@@ -0,0 +1,164 @@
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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connect.js","sourceRoot":"","sources":["../../src/cmd/connect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { Argv } from "yargs";
2
+ type InviteArgs = {
3
+ email: string;
4
+ "persona-surface": string;
5
+ "persona-workflow"?: string;
6
+ org?: string;
7
+ api: string;
8
+ };
9
+ export declare const inviteCommand: {
10
+ command: string;
11
+ describe: string;
12
+ builder: (yargs: Argv) => Argv<{
13
+ email: string;
14
+ } & {
15
+ "persona-surface": string;
16
+ } & {
17
+ "persona-workflow": string | undefined;
18
+ } & {
19
+ org: string | undefined;
20
+ } & {
21
+ api: string;
22
+ }>;
23
+ handler: (args: InviteArgs) => Promise<void>;
24
+ };
25
+ export {};
26
+ //# sourceMappingURL=invite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invite.d.ts","sourceRoot":"","sources":["../../src/cmd/invite.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAGlC,KAAK,UAAU,GAAG;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB,EAAE,MAAM,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAIF,eAAO,MAAM,aAAa;;;qBAGP,IAAI;;;;;;;;;;;oBAkCC,UAAU;CAsCjC,CAAC"}
@@ -0,0 +1,73 @@
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", "oracle-cowork", "player-web"],
16
+ describe: "Which surface they'll primarily use",
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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invite.js","sourceRoot":"","sources":["../../src/cmd/invite.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAUlD,MAAM,WAAW,GAAG,yBAAyB,CAAC;AAE9C,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,OAAO,EAAE,QAAQ;IACjB,QAAQ,EAAE,sDAAsD;IAChE,OAAO,EAAE,CAAC,KAAW,EAAE,EAAE,CACvB,KAAK;SACF,MAAM,CAAC,OAAO,EAAE;QACf,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,IAAI;QAClB,QAAQ,EAAE,qCAAqC;KAChD,CAAC;SACD,MAAM,CAAC,iBAAiB,EAAE;QACzB,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,IAAI;QAClB,OAAO,EAAE,CAAC,kBAAkB,EAAE,eAAe,EAAE,YAAY,CAAC;QAC5D,QAAQ,EAAE,qCAAqC;KAChD,CAAC;SACD,MAAM,CAAC,kBAAkB,EAAE;QAC1B,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE;YACP,UAAU;YACV,WAAW;YACX,qBAAqB;YACrB,eAAe;YACf,WAAW;YACX,YAAY;SACb;QACD,QAAQ,EAAE,wBAAwB;KACnC,CAAC;SACD,MAAM,CAAC,KAAK,EAAE;QACb,IAAI,EAAE,QAAQ;QACd,QAAQ,EAAE,2DAA2D;KACtE,CAAC;SACD,MAAM,CAAC,KAAK,EAAE;QACb,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,WAAW;QACpB,QAAQ,EAAE,YAAY;KACvB,CAAC;IACN,OAAO,EAAE,KAAK,EAAE,IAAgB,EAAE,EAAE;QAClC,MAAM,KAAK,GAAG,MAAM,QAAQ,EAAE,CAAC;QAC/B,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,KAAK,CACX,2EAA2E,CAC5E,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,qBAAqB,EAAE;YACxD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,UAAU,KAAK,EAAE;aACjC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,eAAe,EAAE,IAAI,CAAC,iBAAiB,CAAC;gBACxC,gBAAgB,EAAE,IAAI,CAAC,kBAAkB,CAAC;gBAC1C,QAAQ,EAAE,IAAI,CAAC,GAAG;aACnB,CAAC;SACH,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;YAC7B,OAAO,CAAC,KAAK,CAAC,4BAA4B,GAAG,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC,CAAC;YAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;QACzD,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC;QACpD,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC1B,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC;QACvD,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;QAClC,OAAO,CAAC,GAAG,CACT,0EAA0E,CAC3E,CAAC;IACJ,CAAC;CACF,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { Argv } from "yargs";
2
+ type JoinArgs = {
3
+ token: string;
4
+ api: string;
5
+ host?: string;
6
+ };
7
+ export declare const joinCommand: {
8
+ command: string;
9
+ describe: string;
10
+ builder: (yargs: Argv) => Argv<{
11
+ token: string;
12
+ } & {
13
+ api: string;
14
+ } & {
15
+ host: string | undefined;
16
+ }>;
17
+ handler: (args: JoinArgs) => Promise<void>;
18
+ };
19
+ export {};
20
+ //# sourceMappingURL=join.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"join.d.ts","sourceRoot":"","sources":["../../src/cmd/join.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAKlC,KAAK,QAAQ,GAAG;IACd,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAyBF,eAAO,MAAM,WAAW;;;qBAGL,IAAI;;;;;;;oBASC,QAAQ;CA0F/B,CAAC"}
@@ -0,0 +1,91 @@
1
+ import { setTimeout as sleep } from "node:timers/promises";
2
+ import { openBrowser } from "../auth/browser-flow.js";
3
+ import { setToken } from "../sync/credentials.js";
4
+ const API_DEFAULT = "https://app.unfairly.ai";
5
+ export const joinCommand = {
6
+ command: "join <token>",
7
+ describe: "Join an Unfairly org via a persona-tagged invite token",
8
+ builder: (yargs) => yargs
9
+ .positional("token", { type: "string", demandOption: true })
10
+ .option("api", { type: "string", default: API_DEFAULT })
11
+ .option("host", {
12
+ type: "string",
13
+ choices: ["claude-code", "codex", "cowork"],
14
+ describe: "Force a specific host (default: pick by persona)",
15
+ }),
16
+ handler: async (args) => {
17
+ // 1. Init session
18
+ console.log("✦ Initializing join session…");
19
+ const initRes = await fetch(`${args.api}/api/cli/join/init`, {
20
+ method: "POST",
21
+ headers: { "Content-Type": "application/json" },
22
+ body: JSON.stringify({ token: args.token }),
23
+ });
24
+ if (!initRes.ok) {
25
+ const err = await initRes.text();
26
+ console.error(`Failed to init: ${initRes.status} ${err}`);
27
+ process.exit(1);
28
+ }
29
+ const init = await initRes.json();
30
+ // 2. Open browser
31
+ console.log(`✓ Opening browser to authorize…`);
32
+ console.log(` (if it doesn't open: ${init.auth_url})`);
33
+ openBrowser(init.auth_url);
34
+ // 3. Poll for completion
35
+ let waited = 0;
36
+ let interval = init.poll_interval_seconds * 1000;
37
+ let result = null;
38
+ while (waited < init.ttl_seconds * 1000) {
39
+ await sleep(interval);
40
+ waited += interval;
41
+ const pollRes = await fetch(init.poll_url);
42
+ if (!pollRes.ok) {
43
+ console.error(`Poll error: ${pollRes.status}`);
44
+ process.exit(1);
45
+ }
46
+ const poll = await pollRes.json();
47
+ if (poll.status === "completed") {
48
+ result = poll;
49
+ break;
50
+ }
51
+ if (poll.status === "expired") {
52
+ console.error("Session expired. Re-run the command.");
53
+ process.exit(1);
54
+ }
55
+ if (waited > init.poll_backoff_after_seconds * 1000) {
56
+ interval = init.poll_backoff_interval_seconds * 1000;
57
+ }
58
+ }
59
+ if (!result) {
60
+ console.error("Timed out waiting for browser auth. Re-run the command.");
61
+ process.exit(1);
62
+ }
63
+ console.log(`✓ You're in. Joining as: ${result.display_name} (${result.persona_surface}/${result.persona_workflow ?? "—"})`);
64
+ // 4. Pick host (default by persona surface)
65
+ const host = args.host ??
66
+ (result.persona_surface === "oracle-cowork" ? "cowork" : "claude-code");
67
+ // 5. Persist the join JWT via existing credential store + configure host.
68
+ // Existing host writers take a single `apiUrl: string` arg and read
69
+ // the token from credentials.
70
+ await setToken(result.jwt);
71
+ console.log(`✓ Configuring ${host}…`);
72
+ if (host === "claude-code") {
73
+ const { configureClaudeCode } = await import("../hosts/claude-code.js");
74
+ await configureClaudeCode(args.api, result.jwt);
75
+ }
76
+ else if (host === "codex") {
77
+ const { configureCodex } = await import("../hosts/codex.js");
78
+ await configureCodex(args.api);
79
+ }
80
+ else if (host === "cowork") {
81
+ const { configureClaudeDesktop } = await import("../hosts/claude-desktop.js");
82
+ await configureClaudeDesktop(args.api, result.jwt);
83
+ console.log("⚠ Quit and relaunch Claude Desktop to load the new MCP server.");
84
+ }
85
+ // 6. Print persona-shaped welcome
86
+ const welcomeRes = await fetch(`${args.api}/api/cli/welcome?persona=${result.persona_surface}&workflow=${result.persona_workflow ?? ""}`);
87
+ const welcome = await welcomeRes.text();
88
+ console.log(welcome);
89
+ },
90
+ };
91
+ //# sourceMappingURL=join.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"join.js","sourceRoot":"","sources":["../../src/cmd/join.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export type ParsedShareInput = {
2
+ shareId: string;
3
+ origin: string | null;
4
+ };
5
+ export declare function parseShareInput(input: string): ParsedShareInput;
6
+ //# sourceMappingURL=parse-share-input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-share-input.d.ts","sourceRoot":"","sources":["../../src/cmd/parse-share-input.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,CA+C/D"}
@@ -0,0 +1,56 @@
1
+ // cli/src/cmd/parse-share-input.ts
2
+ //
3
+ // Parse the positional arg to `unfairly connect`. Accepts:
4
+ // - Full URL: https://app.unfairly.ai/s/<uuid>
5
+ // - Short form: s/<uuid>
6
+ // - Bare UUID: <uuid>
7
+ //
8
+ // Returns the share_link UUID + the origin (when present in the input)
9
+ // so `connect` can POST to the same host the link came from. A bare UUID
10
+ // or short form yields `origin: null` — callers should fall back to the
11
+ // production app origin.
12
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
13
+ export function parseShareInput(input) {
14
+ if (typeof input !== "string") {
15
+ throw new Error("share link is required");
16
+ }
17
+ const trimmed = input.trim();
18
+ if (trimmed.length === 0) {
19
+ throw new Error("share link is required");
20
+ }
21
+ // Full URL form: https://host/s/<uuid> (with optional trailing slash / query).
22
+ if (/^https?:\/\//i.test(trimmed)) {
23
+ let url;
24
+ try {
25
+ url = new URL(trimmed);
26
+ }
27
+ catch {
28
+ throw new Error(`not a valid URL: ${trimmed}`);
29
+ }
30
+ const segments = url.pathname.split("/").filter(Boolean);
31
+ // Expect [..., "s", "<uuid>"] — find the "s/" marker.
32
+ const sIdx = segments.indexOf("s");
33
+ if (sIdx === -1 || sIdx === segments.length - 1) {
34
+ throw new Error(`share link URL must include /s/<id>: ${trimmed}`);
35
+ }
36
+ const candidate = segments[sIdx + 1] ?? "";
37
+ if (!UUID_RE.test(candidate)) {
38
+ throw new Error(`share id must be a UUID, got "${candidate}"`);
39
+ }
40
+ return { shareId: candidate.toLowerCase(), origin: url.origin };
41
+ }
42
+ // Short form: s/<uuid>
43
+ if (/^s\//i.test(trimmed)) {
44
+ const candidate = trimmed.slice(2);
45
+ if (!UUID_RE.test(candidate)) {
46
+ throw new Error(`share id must be a UUID, got "${candidate}"`);
47
+ }
48
+ return { shareId: candidate.toLowerCase(), origin: null };
49
+ }
50
+ // Bare UUID
51
+ if (UUID_RE.test(trimmed)) {
52
+ return { shareId: trimmed.toLowerCase(), origin: null };
53
+ }
54
+ throw new Error(`not a recognized share link: "${input}" — expected a URL like https://app.unfairly.ai/s/<uuid>, "s/<uuid>", or a bare UUID`);
55
+ }
56
+ //# sourceMappingURL=parse-share-input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-share-input.js","sourceRoot":"","sources":["../../src/cmd/parse-share-input.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,EAAE;AACF,2DAA2D;AAC3D,kDAAkD;AAClD,2BAA2B;AAC3B,yBAAyB;AACzB,EAAE;AACF,uEAAuE;AACvE,yEAAyE;AACzE,wEAAwE;AACxE,yBAAyB;AAEzB,MAAM,OAAO,GAAG,iEAAiE,CAAC;AAOlF,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;IAED,+EAA+E;IAC/E,IAAI,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAClC,IAAI,GAAQ,CAAC;QACb,IAAI,CAAC;YACH,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;QACzB,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAC;QACjD,CAAC;QACD,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACzD,sDAAsD;QACtD,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,IAAI,KAAK,CAAC,CAAC,IAAI,IAAI,KAAK,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChD,MAAM,IAAI,KAAK,CAAC,wCAAwC,OAAO,EAAE,CAAC,CAAC;QACrE,CAAC;QACD,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3C,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,iCAAiC,SAAS,GAAG,CAAC,CAAC;QACjE,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC;IAClE,CAAC;IAED,uBAAuB;IACvB,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1B,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACnC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,iCAAiC,SAAS,GAAG,CAAC,CAAC;QACjE,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAC5D,CAAC;IAED,YAAY;IACZ,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1B,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAC1D,CAAC;IAED,MAAM,IAAI,KAAK,CACb,iCAAiC,KAAK,sFAAsF,CAC7H,CAAC;AACJ,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { type AddScopedEntryInput, type AddScopedEntryResult } from "./claude-desktop.js";
1
2
  export type ClaudeCodeResult = {
2
3
  status: "configured";
3
4
  path: string;
@@ -57,5 +58,18 @@ export declare function mergeIntoConfig(existing: ClaudeConfig, apiUrl: string,
57
58
  * `claude mcp add` would have done implicitly.
58
59
  */
59
60
  export declare function configureClaudeCode(apiUrl: string, token: string): Promise<ClaudeCodeResult>;
61
+ /**
62
+ * Add a scoped, per-share_link MCP entry to Claude Code's ~/.claude.json.
63
+ * Reuses the Claude Desktop entry-shape + key-picker logic (same JSON
64
+ * config format). Idempotent by `_meta.shareLinkId`.
65
+ *
66
+ * If the `claude` binary is not in PATH → not-installed (we don't create
67
+ * ~/.claude.json out of thin air for a user who hasn't installed Claude
68
+ * Code yet — matches `configureClaudeCode` behavior).
69
+ *
70
+ * If the binary exists but ~/.claude.json doesn't → create it with the
71
+ * scoped entry (fresh-install case).
72
+ */
73
+ export declare function addScopedClaudeCodeEntry(input: AddScopedEntryInput): Promise<AddScopedEntryResult>;
60
74
  export {};
61
75
  //# sourceMappingURL=claude-code.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../src/hosts/claude-code.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,gBAAgB,GACxB;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,MAAM,EAAE,eAAe,CAAA;CAAE,GAC3B;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzC,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE;QAAE,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;CACpC,CAAC;AAEF,KAAK,YAAY,GAAG;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;IACpE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe,CAMzE;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,YAAY,EACtB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,YAAY,CAuBd;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,gBAAgB,CAAC,CA6C3B"}
1
+ {"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../src/hosts/claude-code.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EAC1B,MAAM,qBAAqB,CAAC;AAE7B,MAAM,MAAM,gBAAgB,GACxB;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,MAAM,EAAE,eAAe,CAAA;CAAE,GAC3B;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzC,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE;QAAE,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;CACpC,CAAC;AAEF,KAAK,YAAY,GAAG;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;IACpE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe,CAMzE;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,YAAY,EACtB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,YAAY,CAuBd;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,gBAAgB,CAAC,CA6C3B;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,mBAAmB,GACzB,OAAO,CAAC,oBAAoB,CAAC,CAgD/B"}