unfairly 0.2.0 → 0.5.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.
Files changed (115) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +45 -1
  3. package/dist/auth/browser-flow.d.ts +15 -0
  4. package/dist/auth/browser-flow.d.ts.map +1 -0
  5. package/dist/auth/browser-flow.js +74 -0
  6. package/dist/auth/browser-flow.js.map +1 -0
  7. package/dist/cmd/init.d.ts +10 -0
  8. package/dist/cmd/init.d.ts.map +1 -0
  9. package/dist/cmd/init.js +12 -92
  10. package/dist/cmd/init.js.map +1 -0
  11. package/dist/cmd/login.d.ts +21 -0
  12. package/dist/cmd/login.d.ts.map +1 -0
  13. package/dist/cmd/login.js +13 -67
  14. package/dist/cmd/login.js.map +1 -0
  15. package/dist/cmd/mcp.d.ts +2 -0
  16. package/dist/cmd/mcp.d.ts.map +1 -0
  17. package/dist/cmd/mcp.js +1 -0
  18. package/dist/cmd/mcp.js.map +1 -0
  19. package/dist/cmd/pull.d.ts +2 -0
  20. package/dist/cmd/pull.d.ts.map +1 -0
  21. package/dist/cmd/pull.js +9 -0
  22. package/dist/cmd/pull.js.map +1 -0
  23. package/dist/cmd/push.d.ts +2 -0
  24. package/dist/cmd/push.d.ts.map +1 -0
  25. package/dist/cmd/push.js +1 -0
  26. package/dist/cmd/push.js.map +1 -0
  27. package/dist/cmd/resolve.d.ts +2 -0
  28. package/dist/cmd/resolve.d.ts.map +1 -0
  29. package/dist/cmd/resolve.js +1 -0
  30. package/dist/cmd/resolve.js.map +1 -0
  31. package/dist/cmd/setup.d.ts +20 -0
  32. package/dist/cmd/setup.d.ts.map +1 -0
  33. package/dist/cmd/setup.js +151 -0
  34. package/dist/cmd/setup.js.map +1 -0
  35. package/dist/cmd/status.d.ts +2 -0
  36. package/dist/cmd/status.d.ts.map +1 -0
  37. package/dist/cmd/status.js +1 -0
  38. package/dist/cmd/status.js.map +1 -0
  39. package/dist/cmd/watch.d.ts +2 -0
  40. package/dist/cmd/watch.d.ts.map +1 -0
  41. package/dist/cmd/watch.js +1 -0
  42. package/dist/cmd/watch.js.map +1 -0
  43. package/dist/hosts/claude-code.d.ts +23 -0
  44. package/dist/hosts/claude-code.d.ts.map +1 -0
  45. package/dist/hosts/claude-code.js +44 -0
  46. package/dist/hosts/claude-code.js.map +1 -0
  47. package/dist/hosts/codex.d.ts +39 -0
  48. package/dist/hosts/codex.d.ts.map +1 -0
  49. package/dist/hosts/codex.js +97 -0
  50. package/dist/hosts/codex.js.map +1 -0
  51. package/dist/hosts/shell-env.d.ts +16 -0
  52. package/dist/hosts/shell-env.d.ts.map +1 -0
  53. package/dist/hosts/shell-env.js +81 -0
  54. package/dist/hosts/shell-env.js.map +1 -0
  55. package/dist/index.d.ts +3 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +5 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/lib/client.d.ts +46 -0
  60. package/dist/lib/client.d.ts.map +1 -0
  61. package/dist/lib/client.js +58 -0
  62. package/dist/lib/client.js.map +1 -0
  63. package/dist/lib/events/emit.d.ts +16 -0
  64. package/dist/lib/events/emit.d.ts.map +1 -0
  65. package/dist/lib/events/emit.js +27 -0
  66. package/dist/lib/events/emit.js.map +1 -0
  67. package/dist/lib/index.d.ts +13 -0
  68. package/dist/lib/index.d.ts.map +1 -0
  69. package/dist/lib/index.js +11 -0
  70. package/dist/lib/index.js.map +1 -0
  71. package/dist/lib/transport.d.ts +46 -0
  72. package/dist/lib/transport.d.ts.map +1 -0
  73. package/dist/lib/transport.js +85 -0
  74. package/dist/lib/transport.js.map +1 -0
  75. package/dist/lib/types/index.d.ts +167 -0
  76. package/dist/lib/types/index.d.ts.map +1 -0
  77. package/dist/lib/types/index.js +50 -0
  78. package/dist/lib/types/index.js.map +1 -0
  79. package/dist/lib/vault/checkpoint.d.ts +12 -0
  80. package/dist/lib/vault/checkpoint.d.ts.map +1 -0
  81. package/dist/lib/vault/checkpoint.js +18 -0
  82. package/dist/lib/vault/checkpoint.js.map +1 -0
  83. package/dist/lib/vault/read.d.ts +4 -0
  84. package/dist/lib/vault/read.d.ts.map +1 -0
  85. package/dist/lib/vault/read.js +9 -0
  86. package/dist/lib/vault/read.js.map +1 -0
  87. package/dist/lib/vault/search.d.ts +8 -0
  88. package/dist/lib/vault/search.d.ts.map +1 -0
  89. package/dist/lib/vault/search.js +10 -0
  90. package/dist/lib/vault/search.js.map +1 -0
  91. package/dist/sync/api.d.ts +80 -0
  92. package/dist/sync/api.d.ts.map +1 -0
  93. package/dist/sync/api.js +1 -0
  94. package/dist/sync/api.js.map +1 -0
  95. package/dist/sync/autoloader.d.ts +7 -0
  96. package/dist/sync/autoloader.d.ts.map +1 -0
  97. package/dist/sync/autoloader.js +138 -0
  98. package/dist/sync/autoloader.js.map +1 -0
  99. package/dist/sync/conflict.d.ts +12 -0
  100. package/dist/sync/conflict.d.ts.map +1 -0
  101. package/dist/sync/conflict.js +1 -0
  102. package/dist/sync/conflict.js.map +1 -0
  103. package/dist/sync/credentials.d.ts +8 -0
  104. package/dist/sync/credentials.d.ts.map +1 -0
  105. package/dist/sync/credentials.js +1 -0
  106. package/dist/sync/credentials.js.map +1 -0
  107. package/dist/sync/files.d.ts +43 -0
  108. package/dist/sync/files.d.ts.map +1 -0
  109. package/dist/sync/files.js +1 -0
  110. package/dist/sync/files.js.map +1 -0
  111. package/dist/sync/manifest.d.ts +31 -0
  112. package/dist/sync/manifest.d.ts.map +1 -0
  113. package/dist/sync/manifest.js +1 -0
  114. package/dist/sync/manifest.js.map +1 -0
  115. package/package.json +26 -5
@@ -0,0 +1,151 @@
1
+ import { browserAuthFlow } from "../auth/browser-flow.js";
2
+ import { setToken } from "../sync/credentials.js";
3
+ import { writeShellEnv } from "../hosts/shell-env.js";
4
+ import { configureCodex } from "../hosts/codex.js";
5
+ import { configureClaudeCode, } from "../hosts/claude-code.js";
6
+ const DEFAULT_API = "https://app.unfairly.ai";
7
+ /**
8
+ * `unfairly setup` — one-shot agent host installer.
9
+ *
10
+ * 1. Browser OAuth → mint mcp_* token, cache in keychain.
11
+ * 2. Append/replace a sentinel-marked block in the user's shell rcfile
12
+ * (~/.zshenv on zsh, ~/.bash_profile on bash) with UNFAIRLY_MCP_TOKEN
13
+ * + UNFAIRLY_TOKEN exports.
14
+ * 3. Patch ~/.codex/config.toml with [mcp_servers.unfairly] including
15
+ * bearer_token_env_var. Skips silently if Codex isn't installed.
16
+ * 4. Register with Claude Code via `claude mcp add` if the binary is
17
+ * in PATH. Non-destructive — tolerates "already exists" as success.
18
+ * 5. Verify the new token works by calling /api/mcp with it. If the
19
+ * handshake fails, print clear remediation instructions instead of
20
+ * declaring victory.
21
+ *
22
+ * Idempotent — safe to re-run any time. Each write replaces in place
23
+ * rather than duplicating.
24
+ */
25
+ export async function runSetup() {
26
+ const apiUrl = process.env.UNFAIRLY_API_URL ?? DEFAULT_API;
27
+ console.error("✦ unfairly setup");
28
+ console.error("");
29
+ // Step 1: browser auth
30
+ console.error("[1/4] Authorizing in browser...");
31
+ const token = await browserAuthFlow(apiUrl, { tokenName: "unfairly setup" });
32
+ if (!token) {
33
+ console.error(" ✗ Browser flow timed out or was cancelled. Run `unfairly setup` again.");
34
+ process.exit(1);
35
+ }
36
+ await setToken(token);
37
+ console.error(" ✓ Token minted and cached in keychain");
38
+ console.error("");
39
+ // Step 2: shell env
40
+ console.error("[2/4] Writing shell config...");
41
+ const env = await writeShellEnv(token);
42
+ if (env.shell === "unknown") {
43
+ console.error(" ⚠ Couldn't detect your shell ($SHELL is empty or non-zsh/bash).");
44
+ console.error(" Add this to your shell config manually:");
45
+ console.error(` export UNFAIRLY_MCP_TOKEN=${token}`);
46
+ }
47
+ else {
48
+ console.error(` ✓ ${env.path} (${env.action}) [${env.shell}]`);
49
+ }
50
+ console.error("");
51
+ // Step 3: hosts
52
+ console.error("[3/4] Configuring agent hosts...");
53
+ const codex = await configureCodex(apiUrl);
54
+ console.error(` ${formatCodex(codex)}`);
55
+ const cc = await configureClaudeCode(apiUrl);
56
+ console.error(` ${formatClaudeCode(cc)}`);
57
+ console.error("");
58
+ // Step 4: verify
59
+ console.error("[4/4] Verifying token works against /api/mcp...");
60
+ const verified = await verifyToken(apiUrl, token);
61
+ if (verified.ok) {
62
+ console.error(" ✓ MCP handshake succeeded");
63
+ }
64
+ else {
65
+ console.error(` ✗ MCP handshake FAILED — ${verified.message}`);
66
+ console.error(" The token was saved, but something is wrong. Check that you signed in");
67
+ console.error(" as an internal-team member (anyone outside the allowlist gets denied).");
68
+ process.exit(2);
69
+ }
70
+ console.error("");
71
+ // Next steps
72
+ console.error("✓ Setup complete.");
73
+ console.error("");
74
+ console.error("Next:");
75
+ console.error(" 1. Open a NEW terminal (existing shells don't have $UNFAIRLY_MCP_TOKEN yet).");
76
+ if (codex.status === "configured" || cc.status === "configured") {
77
+ console.error(" 2. Restart any running agent host (Codex, Claude Code) so it reloads the MCP config.");
78
+ console.error(" 3. Send any prompt — the agent will auto-fire `enter_org` and show your vaults.");
79
+ }
80
+ else {
81
+ console.error(" 2. Install Codex or Claude Code, then re-run `unfairly setup` to wire them up.");
82
+ }
83
+ console.error("");
84
+ console.error("Optional — pull all vaults to local markdown for fast filesystem reads:");
85
+ console.error(" cd <your-workspace> && unfairly init");
86
+ }
87
+ function formatCodex(r) {
88
+ switch (r.status) {
89
+ case "configured":
90
+ return `✓ Codex (${r.path}) — ${r.action}`;
91
+ case "not-installed":
92
+ return `· Codex not detected at ${r.path} (skipped — install Codex and re-run if you want it)`;
93
+ case "error":
94
+ return `✗ Codex — ${r.message}`;
95
+ }
96
+ }
97
+ function formatClaudeCode(r) {
98
+ switch (r.status) {
99
+ case "configured":
100
+ return `✓ Claude Code — ${r.message}`;
101
+ case "already-registered":
102
+ return `· Claude Code — ${r.message}`;
103
+ case "not-installed":
104
+ return "· Claude Code CLI not detected (skipped)";
105
+ case "error":
106
+ return `✗ Claude Code — ${r.message}`;
107
+ }
108
+ }
109
+ /**
110
+ * Hit /api/mcp with the new token to confirm the full chain works:
111
+ * token row written, /api/mcp accepts it, handshake completes.
112
+ *
113
+ * We do an MCP `initialize` — that's the cheapest call that exercises
114
+ * the auth path end-to-end without touching DB-heavy tools.
115
+ */
116
+ async function verifyToken(apiUrl, token) {
117
+ const url = `${apiUrl.replace(/\/$/, "")}/api/mcp`;
118
+ try {
119
+ const res = await fetch(url, {
120
+ method: "POST",
121
+ headers: {
122
+ Authorization: `Bearer ${token}`,
123
+ "Content-Type": "application/json",
124
+ Accept: "application/json, text/event-stream",
125
+ },
126
+ body: JSON.stringify({
127
+ jsonrpc: "2.0",
128
+ id: 1,
129
+ method: "initialize",
130
+ params: {
131
+ protocolVersion: "2024-11-05",
132
+ capabilities: {},
133
+ clientInfo: { name: "unfairly-setup", version: "0.3.0" },
134
+ },
135
+ }),
136
+ });
137
+ if (res.status !== 200) {
138
+ return { ok: false, message: `HTTP ${res.status}` };
139
+ }
140
+ const text = await res.text();
141
+ if (!text.includes('"result"') || !text.includes("protocolVersion")) {
142
+ return { ok: false, message: "unexpected response shape" };
143
+ }
144
+ return { ok: true };
145
+ }
146
+ catch (e) {
147
+ const err = e;
148
+ return { ok: false, message: err.message };
149
+ }
150
+ }
151
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/cmd/setup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function runStatus(): Promise<void>;
2
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/cmd/status.ts"],"names":[],"mappings":"AAIA,wBAAsB,SAAS,kBAqB9B"}
@@ -23,3 +23,4 @@ export async function runStatus() {
23
23
  console.log(`${slug.padEnd(20)} pulled ${pulled} · pushed ${pushed} · modified ${modified}`);
24
24
  }
25
25
  }
26
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/cmd/status.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE1D,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC;IACzC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,CAAC,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACjE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACxD,IAAI,QAAQ,GAAG,CAAC,CAAC;QACjB,KAAK,MAAM,CAAC,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/C,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;gBACtE,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,GAAG;oBAAE,QAAQ,EAAE,CAAC;YAChD,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;QACZ,CAAC;QACD,MAAM,MAAM,GAAG,CAAC,CAAC,cAAc,IAAI,OAAO,CAAC;QAC3C,MAAM,MAAM,GAAG,CAAC,CAAC,cAAc,IAAI,OAAO,CAAC;QAC3C,OAAO,CAAC,GAAG,CACT,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,WAAW,MAAM,aAAa,MAAM,eAAe,QAAQ,EAAE,CAChF,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function runWatch(): Promise<void>;
2
+ //# sourceMappingURL=watch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/cmd/watch.ts"],"names":[],"mappings":"AAIA,wBAAsB,QAAQ,kBA0B7B"}
package/dist/cmd/watch.js CHANGED
@@ -23,3 +23,4 @@ export async function runWatch() {
23
23
  .on("add", debouncePush);
24
24
  await new Promise(() => { }); // keep alive until SIGINT
25
25
  }
26
+ //# sourceMappingURL=watch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.js","sourceRoot":"","sources":["../../src/cmd/watch.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,CAAC,KAAK,UAAU,QAAQ;IAC5B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IAExC,OAAO,CAAC,GAAG,CAAC,YAAY,GAAG,mBAAmB,CAAC,CAAC;IAEhD,IAAI,KAAK,GAA0B,IAAI,CAAC;IACxC,MAAM,YAAY,GAAG,GAAG,EAAE;QACxB,IAAI,KAAK;YAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QAC/B,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YACtB,OAAO,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAQ,EAAE,EAAE,CACpC,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC,CAAC,OAAO,CAAC,CACzC,CAAC;QACJ,CAAC,EAAE,IAAI,CAAC,CAAC;IACX,CAAC,CAAC;IAEF,QAAQ;SACL,KAAK,CAAC,GAAG,EAAE;QACV,OAAO,EAAE,CAAC,eAAe,EAAE,iBAAiB,EAAE,SAAS,CAAC;QACxD,aAAa,EAAE,IAAI;QACnB,UAAU,EAAE,IAAI;KACjB,CAAC;SACD,EAAE,CAAC,QAAQ,EAAE,YAAY,CAAC;SAC1B,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;IAE3B,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,CAAC,0BAA0B;AACzD,CAAC"}
@@ -0,0 +1,23 @@
1
+ export type ClaudeCodeResult = {
2
+ status: "configured";
3
+ message: string;
4
+ } | {
5
+ status: "already-registered";
6
+ message: string;
7
+ } | {
8
+ status: "not-installed";
9
+ } | {
10
+ status: "error";
11
+ message: string;
12
+ };
13
+ /**
14
+ * Register Unfairly with Claude Code via `claude mcp add`. Non-destructive:
15
+ * if a server named `unfairly` already exists we don't remove it (the user
16
+ * may have a custom config). Instead we tolerate the "already exists" error
17
+ * and report `already-registered`.
18
+ *
19
+ * Skips silently if the `claude` binary is not in PATH (most CLI users have
20
+ * one host installed, not both).
21
+ */
22
+ export declare function configureClaudeCode(apiUrl: string): Promise<ClaudeCodeResult>;
23
+ //# sourceMappingURL=claude-code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../src/hosts/claude-code.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,gBAAgB,GACxB;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,MAAM,EAAE,oBAAoB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,MAAM,EAAE,eAAe,CAAA;CAAE,GAC3B;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzC;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,gBAAgB,CAAC,CA2C3B"}
@@ -0,0 +1,44 @@
1
+ import { spawnSync } from "node:child_process";
2
+ /**
3
+ * Register Unfairly with Claude Code via `claude mcp add`. Non-destructive:
4
+ * if a server named `unfairly` already exists we don't remove it (the user
5
+ * may have a custom config). Instead we tolerate the "already exists" error
6
+ * and report `already-registered`.
7
+ *
8
+ * Skips silently if the `claude` binary is not in PATH (most CLI users have
9
+ * one host installed, not both).
10
+ */
11
+ export async function configureClaudeCode(apiUrl) {
12
+ const url = `${apiUrl.replace(/\/$/, "")}/api/mcp`;
13
+ const result = spawnSync("claude", ["mcp", "add", "unfairly", "--transport", "http", url], { encoding: "utf-8" });
14
+ if (result.error) {
15
+ const e = result.error;
16
+ if (e.code === "ENOENT") {
17
+ return { status: "not-installed" };
18
+ }
19
+ return { status: "error", message: e.message };
20
+ }
21
+ const stderr = (result.stderr ?? "").toString();
22
+ const stdout = (result.stdout ?? "").toString();
23
+ const combined = `${stderr}\n${stdout}`.toLowerCase();
24
+ if (result.status === 0) {
25
+ return {
26
+ status: "configured",
27
+ message: "registered (Claude Code will pop OAuth on first call)",
28
+ };
29
+ }
30
+ // Claude CLI exits non-zero with a stderr message containing "already
31
+ // exists" (or similar) when the server name is taken. Don't destroy the
32
+ // user's existing config — surface as already-registered.
33
+ if (/already exists|already configured|duplicate/.test(combined)) {
34
+ return {
35
+ status: "already-registered",
36
+ message: "already registered (left as-is)",
37
+ };
38
+ }
39
+ return {
40
+ status: "error",
41
+ message: stderr.trim() || `claude mcp add exited ${result.status}`,
42
+ };
43
+ }
44
+ //# sourceMappingURL=claude-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../src/hosts/claude-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAQ/C;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAAc;IAEd,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC;IACnD,MAAM,MAAM,GAAG,SAAS,CACtB,QAAQ,EACR,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,CAAC,EACtD,EAAE,QAAQ,EAAE,OAAO,EAAE,CACtB,CAAC;IAEF,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,CAAC,GAAG,MAAM,CAAC,KAA8B,CAAC;QAChD,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACxB,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;QACrC,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;IACjD,CAAC;IAED,MAAM,MAAM,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;IAChD,MAAM,MAAM,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;IAChD,MAAM,QAAQ,GAAG,GAAG,MAAM,KAAK,MAAM,EAAE,CAAC,WAAW,EAAE,CAAC;IAEtD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO;YACL,MAAM,EAAE,YAAY;YACpB,OAAO,EAAE,uDAAuD;SACjE,CAAC;IACJ,CAAC;IAED,sEAAsE;IACtE,wEAAwE;IACxE,0DAA0D;IAC1D,IACE,6CAA6C,CAAC,IAAI,CAAC,QAAQ,CAAC,EAC5D,CAAC;QACD,OAAO;YACL,MAAM,EAAE,oBAAoB;YAC5B,OAAO,EAAE,iCAAiC;SAC3C,CAAC;IACJ,CAAC;IAED,OAAO;QACL,MAAM,EAAE,OAAO;QACf,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,yBAAyB,MAAM,CAAC,MAAM,EAAE;KACnE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,39 @@
1
+ export type CodexResult = {
2
+ status: "configured";
3
+ path: string;
4
+ action: "created" | "appended" | "replaced";
5
+ } | {
6
+ status: "not-installed";
7
+ path: string;
8
+ } | {
9
+ status: "error";
10
+ path: string;
11
+ message: string;
12
+ };
13
+ /**
14
+ * Build the canonical [mcp_servers.unfairly] block. We own this whole
15
+ * section — anything inside it gets overwritten on re-runs.
16
+ */
17
+ export declare function buildCodexBlock(apiUrl: string): string;
18
+ /**
19
+ * Strip ALL existing `[mcp_servers.unfairly]` blocks from a TOML string.
20
+ * "Block" = the section header through (but not including) the next
21
+ * top-level `[...]` table header at column 0, or end-of-file. This also
22
+ * removes any trailing blank lines we previously left.
23
+ *
24
+ * Robust against: duplicate blocks from prior bad runs, CRLF input,
25
+ * blocks at end-of-file with no trailing newline.
26
+ */
27
+ export declare function stripUnfairlyBlocks(toml: string): string;
28
+ /**
29
+ * Patch ~/.codex/config.toml to register the Unfairly MCP server with
30
+ * bearer-token wiring. Idempotent: removes any existing managed block(s)
31
+ * first, then appends one canonical block. Safe against duplicate sections
32
+ * left over from prior bad runs.
33
+ *
34
+ * If ~/.codex/config.toml does not exist, returns {status: "not-installed"}
35
+ * — don't create a Codex config out of thin air for a user who may not
36
+ * have Codex installed.
37
+ */
38
+ export declare function configureCodex(apiUrl: string): Promise<CodexResult>;
39
+ //# sourceMappingURL=codex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../src/hosts/codex.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,WAAW,GACnB;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,UAAU,CAAA;CAAE,GACnF;IAAE,MAAM,EAAE,eAAe,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAIvD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOtD;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAmBxD;AAED;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAiDzE"}
@@ -0,0 +1,97 @@
1
+ import fs from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ const SECTION_HEADER = "[mcp_servers.unfairly]";
5
+ /**
6
+ * Build the canonical [mcp_servers.unfairly] block. We own this whole
7
+ * section — anything inside it gets overwritten on re-runs.
8
+ */
9
+ export function buildCodexBlock(apiUrl) {
10
+ const url = `${apiUrl.replace(/\/$/, "")}/api/mcp`;
11
+ return [
12
+ SECTION_HEADER,
13
+ `url = "${url}"`,
14
+ `bearer_token_env_var = "UNFAIRLY_MCP_TOKEN"`,
15
+ ].join("\n");
16
+ }
17
+ /**
18
+ * Strip ALL existing `[mcp_servers.unfairly]` blocks from a TOML string.
19
+ * "Block" = the section header through (but not including) the next
20
+ * top-level `[...]` table header at column 0, or end-of-file. This also
21
+ * removes any trailing blank lines we previously left.
22
+ *
23
+ * Robust against: duplicate blocks from prior bad runs, CRLF input,
24
+ * blocks at end-of-file with no trailing newline.
25
+ */
26
+ export function stripUnfairlyBlocks(toml) {
27
+ // Normalize CRLF for matching; we'll use the same normalized form for
28
+ // output. (Codex writes LF on macOS / Linux anyway.)
29
+ const normalized = toml.replace(/\r\n/g, "\n");
30
+ // Match each block: header line, then everything up to next top-level
31
+ // [section] header or end-of-string. Multiline mode anchors `^[` to
32
+ // line start. Use `g` to clean up duplicates.
33
+ const blockRe = /^\[mcp_servers\.unfairly\]\s*\n[\s\S]*?(?=^\[|\Z)/gm;
34
+ // Note: `\Z` not supported in JS regex. Substitute with `(?=^\[|$(?![\s\S]))`.
35
+ const jsBlockRe = /^\[mcp_servers\.unfairly\]\s*\n[\s\S]*?(?=^\[|$(?![\s\S]))/gm;
36
+ void blockRe; // documentation only
37
+ let stripped = normalized.replace(jsBlockRe, "");
38
+ // Collapse runs of 3+ blank lines that the strip may have left behind.
39
+ stripped = stripped.replace(/\n{3,}/g, "\n\n");
40
+ return stripped;
41
+ }
42
+ /**
43
+ * Patch ~/.codex/config.toml to register the Unfairly MCP server with
44
+ * bearer-token wiring. Idempotent: removes any existing managed block(s)
45
+ * first, then appends one canonical block. Safe against duplicate sections
46
+ * left over from prior bad runs.
47
+ *
48
+ * If ~/.codex/config.toml does not exist, returns {status: "not-installed"}
49
+ * — don't create a Codex config out of thin air for a user who may not
50
+ * have Codex installed.
51
+ */
52
+ export async function configureCodex(apiUrl) {
53
+ const home = os.homedir();
54
+ const filePath = path.join(home, ".codex", "config.toml");
55
+ let existing;
56
+ try {
57
+ existing = await fs.readFile(filePath, "utf-8");
58
+ }
59
+ catch (err) {
60
+ const e = err;
61
+ if (e.code === "ENOENT") {
62
+ return { status: "not-installed", path: filePath };
63
+ }
64
+ return {
65
+ status: "error",
66
+ path: filePath,
67
+ message: `Could not read ${filePath}: ${e.message}`,
68
+ };
69
+ }
70
+ const hadExistingBlock = /^\[mcp_servers\.unfairly\]/m.test(existing.replace(/\r\n/g, "\n"));
71
+ const stripped = stripUnfairlyBlocks(existing);
72
+ const block = buildCodexBlock(apiUrl);
73
+ // Append, ensuring exactly one blank line of separation if the file is
74
+ // non-empty.
75
+ const trimmedTail = stripped.replace(/\n+$/, "");
76
+ const next = trimmedTail.length === 0
77
+ ? `${block}\n`
78
+ : `${trimmedTail}\n\n${block}\n`;
79
+ try {
80
+ await fs.writeFile(filePath, next, "utf-8");
81
+ }
82
+ catch (err) {
83
+ const e = err;
84
+ return {
85
+ status: "error",
86
+ path: filePath,
87
+ message: `Could not write ${filePath}: ${e.message}`,
88
+ };
89
+ }
90
+ const action = hadExistingBlock
91
+ ? "replaced"
92
+ : existing.length === 0
93
+ ? "created"
94
+ : "appended";
95
+ return { status: "configured", path: filePath, action };
96
+ }
97
+ //# sourceMappingURL=codex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/hosts/codex.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export declare const ENV_BLOCK_START = "# === unfairly cli (auto-managed \u2014 do not edit) ===";
2
+ export declare const ENV_BLOCK_END = "# === end unfairly cli ===";
3
+ export type ShellEnvResult = {
4
+ path: string;
5
+ shell: "zsh" | "bash" | "unknown";
6
+ action: "created" | "appended" | "replaced";
7
+ };
8
+ /**
9
+ * Idempotent shell-env writer. Replaces any existing managed block in
10
+ * place; appends one if none exists. Tolerates CRLF input by normalizing
11
+ * before matching, then preserves the host file's existing line ending
12
+ * convention on write.
13
+ */
14
+ export declare function writeShellEnvFile(rcPath: string, token: string): Promise<"created" | "appended" | "replaced">;
15
+ export declare function writeShellEnv(token: string): Promise<ShellEnvResult>;
16
+ //# sourceMappingURL=shell-env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell-env.d.ts","sourceRoot":"","sources":["../../src/hosts/shell-env.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,eAAe,6DAAwD,CAAC;AACrF,eAAO,MAAM,aAAa,+BAA+B,CAAC;AAE1D,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,KAAK,GAAG,MAAM,GAAG,SAAS,CAAC;IAClC,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,UAAU,CAAC;CAC7C,CAAC;AA+BF;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,SAAS,GAAG,UAAU,GAAG,UAAU,CAAC,CAmC9C;AAED,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAO1E"}
@@ -0,0 +1,81 @@
1
+ import fs from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ export const ENV_BLOCK_START = "# === unfairly cli (auto-managed — do not edit) ===";
5
+ export const ENV_BLOCK_END = "# === end unfairly cli ===";
6
+ /**
7
+ * Detect the user's shell + the right rcfile to write env exports to.
8
+ * Returns null path for unknown shells so the caller can print a manual
9
+ * fallback instead of guessing.
10
+ */
11
+ function detectShell() {
12
+ const shellEnv = process.env.SHELL ?? "";
13
+ const home = os.homedir();
14
+ if (shellEnv.endsWith("zsh")) {
15
+ return { shell: "zsh", rcPath: path.join(home, ".zshenv") };
16
+ }
17
+ if (shellEnv.endsWith("bash")) {
18
+ return { shell: "bash", rcPath: path.join(home, ".bash_profile") };
19
+ }
20
+ return { shell: "unknown", rcPath: null };
21
+ }
22
+ /**
23
+ * Build the canonical sentinel block. Used both for writing and matching.
24
+ */
25
+ function buildBlock(token) {
26
+ return [
27
+ ENV_BLOCK_START,
28
+ `export UNFAIRLY_MCP_TOKEN=${token}`,
29
+ `export UNFAIRLY_TOKEN=${token}`,
30
+ ENV_BLOCK_END,
31
+ ].join("\n");
32
+ }
33
+ /**
34
+ * Idempotent shell-env writer. Replaces any existing managed block in
35
+ * place; appends one if none exists. Tolerates CRLF input by normalizing
36
+ * before matching, then preserves the host file's existing line ending
37
+ * convention on write.
38
+ */
39
+ export async function writeShellEnvFile(rcPath, token) {
40
+ const block = buildBlock(token);
41
+ let existing = "";
42
+ let fileExists = true;
43
+ try {
44
+ existing = await fs.readFile(rcPath, "utf-8");
45
+ }
46
+ catch {
47
+ fileExists = false;
48
+ }
49
+ const normalized = existing.replace(/\r\n/g, "\n");
50
+ const blockRe = new RegExp(`${escapeRegex(ENV_BLOCK_START)}[\\s\\S]*?${escapeRegex(ENV_BLOCK_END)}\\n?`, "g");
51
+ let next;
52
+ let action;
53
+ if (blockRe.test(normalized)) {
54
+ blockRe.lastIndex = 0;
55
+ next = normalized.replace(blockRe, block + "\n");
56
+ action = "replaced";
57
+ }
58
+ else if (!fileExists || normalized.length === 0) {
59
+ next = block + "\n";
60
+ action = "created";
61
+ }
62
+ else {
63
+ const sep = normalized.endsWith("\n") ? "" : "\n";
64
+ next = `${normalized}${sep}\n${block}\n`;
65
+ action = "appended";
66
+ }
67
+ await fs.writeFile(rcPath, next, "utf-8");
68
+ return action;
69
+ }
70
+ export async function writeShellEnv(token) {
71
+ const { shell, rcPath } = detectShell();
72
+ if (!rcPath) {
73
+ return { path: "", shell, action: "created" };
74
+ }
75
+ const action = await writeShellEnvFile(rcPath, token);
76
+ return { path: rcPath, shell, action };
77
+ }
78
+ function escapeRegex(s) {
79
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
80
+ }
81
+ //# sourceMappingURL=shell-env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell-env.js","sourceRoot":"","sources":["../../src/hosts/shell-env.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js CHANGED
@@ -4,6 +4,10 @@ import { hideBin } from "yargs/helpers";
4
4
  await yargs(hideBin(process.argv))
5
5
  .scriptName("unfairly")
6
6
  .usage("$0 <cmd> [args]")
7
+ .command("setup", "One-shot: authorize, write shell env, configure Codex + Claude Code", () => { }, async () => {
8
+ const { runSetup } = await import("./cmd/setup.js");
9
+ await runSetup();
10
+ })
7
11
  .command("login", "Authorize via browser; print export lines for ~/.zshenv (Codex / scripts)", (y) => y.option("quiet", {
8
12
  type: "boolean",
9
13
  alias: "q",
@@ -64,3 +68,4 @@ await yargs(hideBin(process.argv))
64
68
  .strict()
65
69
  .help()
66
70
  .parse();
71
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * `createUnfairlyClient` — public factory for the agent runtime SDK.
3
+ *
4
+ * Resolves API base URL + token from explicit options or env vars. The
5
+ * default base URL is the hosted Unfairly app; self-hosters override it.
6
+ *
7
+ * The returned client is fluent-ish: `client.vault("slug").search(...)`
8
+ * mirrors how the MCP tools read in the wild. Stays HTTP-only — there's
9
+ * no Supabase or admin client in this package. Server work happens at
10
+ * `/api/sdk/v1/*` and reuses the shared `src/lib/vault/*` helpers.
11
+ */
12
+ import { type FetchLike, type TransportFn } from "./transport.js";
13
+ import { makeVaultSearch } from "./vault/search.js";
14
+ import { makeVaultRead } from "./vault/read.js";
15
+ import { makeVaultCheckpoint } from "./vault/checkpoint.js";
16
+ import { makeEmit } from "./events/emit.js";
17
+ import type { MeResponse } from "./types/index.js";
18
+ export type UnfairlyClientOptions = {
19
+ /** MCP token (`mcp_xxx...`). Falls back to `process.env.UNFAIRLY_API_KEY`. */
20
+ apiKey?: string;
21
+ /** Override the API base URL (self-hosted / preview). */
22
+ baseUrl?: string;
23
+ /** Optional fetch impl override (mostly for tests). */
24
+ fetchImpl?: FetchLike;
25
+ /** Per-request timeout in ms. Default 30s. */
26
+ timeoutMs?: number;
27
+ };
28
+ export type VaultClient = {
29
+ search: ReturnType<typeof makeVaultSearch>;
30
+ readDocument: ReturnType<typeof makeVaultRead>;
31
+ checkpoint: ReturnType<typeof makeVaultCheckpoint>;
32
+ };
33
+ export type UnfairlyClient = {
34
+ /** Identify the token owner + the vaults you can reach. */
35
+ me(): Promise<MeResponse>;
36
+ /** Per-vault scoped helpers. */
37
+ vault(slug: string): VaultClient;
38
+ /** Emit a closed-allowlist event into the Unfairly Inngest queue. */
39
+ event: {
40
+ emit: ReturnType<typeof makeEmit>;
41
+ };
42
+ /** Escape hatch for callers that need to call an arbitrary route. */
43
+ raw: TransportFn;
44
+ };
45
+ export declare function createUnfairlyClient(opts?: UnfairlyClientOptions): UnfairlyClient;
46
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/lib/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAmB,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACnF,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAInD,MAAM,MAAM,qBAAqB,GAAG;IAClC,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;IAC3C,YAAY,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;IAC/C,UAAU,EAAE,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC;CACpD,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,2DAA2D;IAC3D,EAAE,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;IAC1B,gCAAgC;IAChC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IACjC,qEAAqE;IACrE,KAAK,EAAE;QAAE,IAAI,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAA;KAAE,CAAC;IAC7C,qEAAqE;IACrE,GAAG,EAAE,WAAW,CAAC;CAClB,CAAC;AAyBF,wBAAgB,oBAAoB,CAClC,IAAI,GAAE,qBAA0B,GAC/B,cAAc,CA0BhB"}