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.
- package/CHANGELOG.md +10 -0
- package/LICENSE +15 -0
- package/README.md +3 -1
- package/dist/auth/browser-flow.d.ts +0 -1
- package/dist/auth/browser-flow.js +5 -81
- package/dist/cmd/connect.d.ts +0 -1
- package/dist/cmd/connect.js +1 -164
- package/dist/cmd/init.d.ts +0 -1
- package/dist/cmd/init.js +2 -138
- package/dist/cmd/invite.d.ts +0 -1
- package/dist/cmd/invite.js +4 -73
- package/dist/cmd/join.d.ts +0 -1
- package/dist/cmd/join.js +1 -91
- package/dist/cmd/login.d.ts +0 -1
- package/dist/cmd/login.js +3 -41
- package/dist/cmd/mcp.d.ts +0 -1
- package/dist/cmd/mcp.js +2 -86
- package/dist/cmd/pace.d.ts +23 -2
- package/dist/cmd/pace.js +4 -393
- package/dist/cmd/parse-share-input.d.ts +0 -1
- package/dist/cmd/parse-share-input.js +1 -56
- package/dist/cmd/pull.d.ts +0 -1
- package/dist/cmd/pull.js +7 -143
- package/dist/cmd/push.d.ts +0 -1
- package/dist/cmd/push.js +1 -85
- package/dist/cmd/resolve.d.ts +0 -1
- package/dist/cmd/resolve.js +1 -35
- package/dist/cmd/setup.d.ts +0 -1
- package/dist/cmd/setup.js +2 -345
- package/dist/cmd/status-card.d.ts +0 -1
- package/dist/cmd/status-card.js +2 -156
- package/dist/cmd/status.d.ts +0 -1
- package/dist/cmd/status.js +3 -29
- package/dist/cmd/watch.d.ts +0 -1
- package/dist/cmd/watch.js +1 -26
- package/dist/hosts/claude-code.d.ts +0 -1
- package/dist/hosts/claude-code.js +3 -180
- package/dist/hosts/claude-desktop.d.ts +0 -1
- package/dist/hosts/claude-desktop.js +3 -222
- package/dist/hosts/codex.d.ts +0 -1
- package/dist/hosts/codex.js +20 -234
- package/dist/hosts/shell-env.d.ts +0 -1
- package/dist/hosts/shell-env.js +9 -81
- package/dist/index.d.ts +0 -1
- package/dist/index.js +14 -206
- package/dist/lib/client.d.ts +0 -1
- package/dist/lib/client.js +1 -58
- package/dist/lib/events/emit.d.ts +0 -1
- package/dist/lib/events/emit.js +1 -28
- package/dist/lib/index.d.ts +0 -1
- package/dist/lib/index.js +1 -11
- package/dist/lib/transport.d.ts +0 -1
- package/dist/lib/transport.js +1 -85
- package/dist/lib/types/index.d.ts +0 -1
- package/dist/lib/types/index.js +1 -50
- package/dist/lib/vault/checkpoint.d.ts +0 -1
- package/dist/lib/vault/checkpoint.js +1 -18
- package/dist/lib/vault/read.d.ts +0 -1
- package/dist/lib/vault/read.js +1 -9
- package/dist/lib/vault/search.d.ts +0 -1
- package/dist/lib/vault/search.js +1 -10
- package/dist/pace/device.d.ts +3 -1
- package/dist/pace/device.js +2 -148
- package/dist/pace/enroll.d.ts +79 -0
- package/dist/pace/enroll.js +2 -0
- package/dist/pace/identity.d.ts +0 -1
- package/dist/pace/identity.js +1 -17
- package/dist/pace/install.d.ts +0 -1
- package/dist/pace/install.js +4 -127
- package/dist/pace/local-evidence.d.ts +0 -1
- package/dist/pace/local-evidence.js +2 -228
- package/dist/pace/local-sessions.d.ts +0 -1
- package/dist/pace/local-sessions.js +1 -254
- package/dist/pace/managed-config.d.ts +0 -1
- package/dist/pace/managed-config.js +8 -102
- package/dist/pace/normalize.d.ts +0 -1
- package/dist/pace/normalize.js +1 -293
- package/dist/pace/repository.d.ts +0 -1
- package/dist/pace/repository.js +2 -120
- package/dist/pace/schema.d.ts +0 -1
- package/dist/pace/schema.js +1 -134
- package/dist/pace/session-summary.d.ts +0 -1
- package/dist/pace/session-summary.js +2 -140
- package/dist/pace/spool.d.ts +0 -1
- package/dist/pace/spool.js +8 -87
- package/dist/pace-runtime.d.ts +1 -0
- package/dist/pace-runtime.js +2 -0
- package/dist/sync/api.d.ts +0 -1
- package/dist/sync/api.js +1 -55
- package/dist/sync/autoloader.d.ts +0 -1
- package/dist/sync/autoloader.js +5 -127
- package/dist/sync/conflict.d.ts +0 -1
- package/dist/sync/conflict.js +5 -15
- package/dist/sync/credentials.d.ts +0 -1
- package/dist/sync/credentials.js +1 -51
- package/dist/sync/files.d.ts +0 -1
- package/dist/sync/files.js +1 -71
- package/dist/sync/manifest.d.ts +0 -1
- package/dist/sync/manifest.js +1 -37
- package/dist/sync/repo-root.d.ts +0 -1
- package/dist/sync/repo-root.js +1 -24
- package/dist/sync/stitch-claude-md.d.ts +0 -1
- package/dist/sync/stitch-claude-md.js +8 -48
- package/dist/ui/colors.d.ts +0 -1
- package/dist/ui/colors.js +1 -28
- package/dist/ui/screens.d.ts +0 -1
- package/dist/ui/screens.js +5 -135
- package/package.json +8 -14
- package/plugin/.cursor-plugin/plugin.json +0 -2
- package/plugin/.mcp.json +1 -1
- package/plugin/LICENSE +15 -0
- package/plugin/README.md +3 -7
- package/plugin/gemini/gemini-extension.json +1 -1
- package/plugin/mcp.json +1 -1
- package/plugin/plugin.json +0 -2
- package/plugin/runtime/unfairly-intelligence.mjs +15 -0
- package/plugin/scripts/capture.cjs +30 -8
- package/plugin/skills/find-company-playbook/SKILL.md +1 -1
- package/dist/auth/browser-flow.d.ts.map +0 -1
- package/dist/auth/browser-flow.js.map +0 -1
- package/dist/cmd/connect.d.ts.map +0 -1
- package/dist/cmd/connect.js.map +0 -1
- package/dist/cmd/init.d.ts.map +0 -1
- package/dist/cmd/init.js.map +0 -1
- package/dist/cmd/invite.d.ts.map +0 -1
- package/dist/cmd/invite.js.map +0 -1
- package/dist/cmd/join.d.ts.map +0 -1
- package/dist/cmd/join.js.map +0 -1
- package/dist/cmd/login.d.ts.map +0 -1
- package/dist/cmd/login.js.map +0 -1
- package/dist/cmd/mcp.d.ts.map +0 -1
- package/dist/cmd/mcp.js.map +0 -1
- package/dist/cmd/pace.d.ts.map +0 -1
- package/dist/cmd/pace.js.map +0 -1
- package/dist/cmd/parse-share-input.d.ts.map +0 -1
- package/dist/cmd/parse-share-input.js.map +0 -1
- package/dist/cmd/pull.d.ts.map +0 -1
- package/dist/cmd/pull.js.map +0 -1
- package/dist/cmd/push.d.ts.map +0 -1
- package/dist/cmd/push.js.map +0 -1
- package/dist/cmd/resolve.d.ts.map +0 -1
- package/dist/cmd/resolve.js.map +0 -1
- package/dist/cmd/setup.d.ts.map +0 -1
- package/dist/cmd/setup.js.map +0 -1
- package/dist/cmd/status-card.d.ts.map +0 -1
- package/dist/cmd/status-card.js.map +0 -1
- package/dist/cmd/status.d.ts.map +0 -1
- package/dist/cmd/status.js.map +0 -1
- package/dist/cmd/watch.d.ts.map +0 -1
- package/dist/cmd/watch.js.map +0 -1
- package/dist/hosts/claude-code.d.ts.map +0 -1
- package/dist/hosts/claude-code.js.map +0 -1
- package/dist/hosts/claude-desktop.d.ts.map +0 -1
- package/dist/hosts/claude-desktop.js.map +0 -1
- package/dist/hosts/codex.d.ts.map +0 -1
- package/dist/hosts/codex.js.map +0 -1
- package/dist/hosts/shell-env.d.ts.map +0 -1
- package/dist/hosts/shell-env.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/client.d.ts.map +0 -1
- package/dist/lib/client.js.map +0 -1
- package/dist/lib/events/emit.d.ts.map +0 -1
- package/dist/lib/events/emit.js.map +0 -1
- package/dist/lib/index.d.ts.map +0 -1
- package/dist/lib/index.js.map +0 -1
- package/dist/lib/transport.d.ts.map +0 -1
- package/dist/lib/transport.js.map +0 -1
- package/dist/lib/types/index.d.ts.map +0 -1
- package/dist/lib/types/index.js.map +0 -1
- package/dist/lib/vault/checkpoint.d.ts.map +0 -1
- package/dist/lib/vault/checkpoint.js.map +0 -1
- package/dist/lib/vault/read.d.ts.map +0 -1
- package/dist/lib/vault/read.js.map +0 -1
- package/dist/lib/vault/search.d.ts.map +0 -1
- package/dist/lib/vault/search.js.map +0 -1
- package/dist/pace/device.d.ts.map +0 -1
- package/dist/pace/device.js.map +0 -1
- package/dist/pace/identity.d.ts.map +0 -1
- package/dist/pace/identity.js.map +0 -1
- package/dist/pace/install.d.ts.map +0 -1
- package/dist/pace/install.js.map +0 -1
- package/dist/pace/local-evidence.d.ts.map +0 -1
- package/dist/pace/local-evidence.js.map +0 -1
- package/dist/pace/local-sessions.d.ts.map +0 -1
- package/dist/pace/local-sessions.js.map +0 -1
- package/dist/pace/managed-config.d.ts.map +0 -1
- package/dist/pace/managed-config.js.map +0 -1
- package/dist/pace/normalize.d.ts.map +0 -1
- package/dist/pace/normalize.js.map +0 -1
- package/dist/pace/repository.d.ts.map +0 -1
- package/dist/pace/repository.js.map +0 -1
- package/dist/pace/schema.d.ts.map +0 -1
- package/dist/pace/schema.js.map +0 -1
- package/dist/pace/session-summary.d.ts.map +0 -1
- package/dist/pace/session-summary.js.map +0 -1
- package/dist/pace/spool.d.ts.map +0 -1
- package/dist/pace/spool.js.map +0 -1
- package/dist/sync/api.d.ts.map +0 -1
- package/dist/sync/api.js.map +0 -1
- package/dist/sync/autoloader.d.ts.map +0 -1
- package/dist/sync/autoloader.js.map +0 -1
- package/dist/sync/conflict.d.ts.map +0 -1
- package/dist/sync/conflict.js.map +0 -1
- package/dist/sync/credentials.d.ts.map +0 -1
- package/dist/sync/credentials.js.map +0 -1
- package/dist/sync/files.d.ts.map +0 -1
- package/dist/sync/files.js.map +0 -1
- package/dist/sync/manifest.d.ts.map +0 -1
- package/dist/sync/manifest.js.map +0 -1
- package/dist/sync/repo-root.d.ts.map +0 -1
- package/dist/sync/repo-root.js.map +0 -1
- package/dist/sync/stitch-claude-md.d.ts.map +0 -1
- package/dist/sync/stitch-claude-md.js.map +0 -1
- package/dist/ui/colors.d.ts.map +0 -1
- package/dist/ui/colors.js.map +0 -1
- package/dist/ui/screens.d.ts.map +0 -1
- package/dist/ui/screens.js.map +0 -1
package/dist/lib/client.js
CHANGED
|
@@ -1,58 +1 @@
|
|
|
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 { createTransport } 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
|
-
const DEFAULT_BASE_URL = "https://app.unfairly.ai";
|
|
18
|
-
function resolveApiKey(opts) {
|
|
19
|
-
const key = opts.apiKey ??
|
|
20
|
-
(typeof process !== "undefined" && process.env
|
|
21
|
-
? process.env.UNFAIRLY_API_KEY ?? process.env.UNFAIRLY_MCP_TOKEN
|
|
22
|
-
: undefined);
|
|
23
|
-
if (!key) {
|
|
24
|
-
throw new Error("unfairly: missing apiKey. Pass `{ apiKey }` or set UNFAIRLY_API_KEY in your environment.");
|
|
25
|
-
}
|
|
26
|
-
return key;
|
|
27
|
-
}
|
|
28
|
-
function resolveBaseUrl(opts) {
|
|
29
|
-
return (opts.baseUrl ??
|
|
30
|
-
(typeof process !== "undefined" && process.env
|
|
31
|
-
? process.env.UNFAIRLY_BASE_URL ?? DEFAULT_BASE_URL
|
|
32
|
-
: DEFAULT_BASE_URL));
|
|
33
|
-
}
|
|
34
|
-
export function createUnfairlyClient(opts = {}) {
|
|
35
|
-
const apiKey = resolveApiKey(opts);
|
|
36
|
-
const baseUrl = resolveBaseUrl(opts);
|
|
37
|
-
const request = createTransport({
|
|
38
|
-
apiKey,
|
|
39
|
-
baseUrl,
|
|
40
|
-
fetchImpl: opts.fetchImpl,
|
|
41
|
-
timeoutMs: opts.timeoutMs,
|
|
42
|
-
});
|
|
43
|
-
const emit = makeEmit(request);
|
|
44
|
-
return {
|
|
45
|
-
me: () => request({
|
|
46
|
-
method: "GET",
|
|
47
|
-
path: "/api/sdk/v1/me",
|
|
48
|
-
}),
|
|
49
|
-
vault: (slug) => ({
|
|
50
|
-
search: makeVaultSearch(request, slug),
|
|
51
|
-
readDocument: makeVaultRead(request, slug),
|
|
52
|
-
checkpoint: makeVaultCheckpoint(request, slug),
|
|
53
|
-
}),
|
|
54
|
-
event: { emit },
|
|
55
|
-
raw: request,
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
//# sourceMappingURL=client.js.map
|
|
1
|
+
import{createTransport as a}from"./transport.js";import{makeVaultSearch as p}from"./vault/search.js";import{makeVaultRead as c}from"./vault/read.js";import{makeVaultCheckpoint as m}from"./vault/checkpoint.js";import{makeEmit as f}from"./events/emit.js";const o="https://app.unfairly.ai";function u(e){const t=e.apiKey??(typeof process<"u"&&process.env?process.env.UNFAIRLY_API_KEY??process.env.UNFAIRLY_MCP_TOKEN:void 0);if(!t)throw new Error("unfairly: missing apiKey. Pass `{ apiKey }` or set UNFAIRLY_API_KEY in your environment.");return t}function l(e){return e.baseUrl??(typeof process<"u"&&process.env?process.env.UNFAIRLY_BASE_URL??o:o)}function A(e={}){const t=u(e),i=l(e),r=a({apiKey:t,baseUrl:i,fetchImpl:e.fetchImpl,timeoutMs:e.timeoutMs}),s=f(r);return{me:()=>r({method:"GET",path:"/api/sdk/v1/me"}),vault:n=>({search:p(r,n),readDocument:c(r,n),checkpoint:m(r,n)}),event:{emit:s},raw:r}}export{A as createUnfairlyClient};
|
package/dist/lib/events/emit.js
CHANGED
|
@@ -1,28 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
export { ALLOWED_EVENT_NAMES, EVENT_PAYLOAD_SCHEMAS, };
|
|
3
|
-
/**
|
|
4
|
-
* Emit a closed-allowlist event to the Unfairly events surface.
|
|
5
|
-
*
|
|
6
|
-
* Client-side validation matches the server's zod schema so callers get
|
|
7
|
-
* a synchronous error before the network round-trip. The server still
|
|
8
|
-
* validates — never trust the client — but this saves a round-trip on
|
|
9
|
-
* dev typos.
|
|
10
|
-
*/
|
|
11
|
-
export function makeEmit(request) {
|
|
12
|
-
return async function emit(event, data) {
|
|
13
|
-
if (!ALLOWED_EVENT_NAMES.includes(event)) {
|
|
14
|
-
throw new Error(`unfairly: unknown event "${event}". Allowed: ${ALLOWED_EVENT_NAMES.join(", ")}`);
|
|
15
|
-
}
|
|
16
|
-
const schema = EVENT_PAYLOAD_SCHEMAS[event];
|
|
17
|
-
const parsed = schema.safeParse(data);
|
|
18
|
-
if (!parsed.success) {
|
|
19
|
-
throw new Error(`unfairly: invalid payload for "${event}": ${JSON.stringify(parsed.error.flatten())}`);
|
|
20
|
-
}
|
|
21
|
-
return request({
|
|
22
|
-
method: "POST",
|
|
23
|
-
path: "/api/sdk/v1/events/emit",
|
|
24
|
-
body: { event, data: parsed.data },
|
|
25
|
-
});
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
//# sourceMappingURL=emit.js.map
|
|
1
|
+
import{ALLOWED_EVENT_NAMES as a,EVENT_PAYLOAD_SCHEMAS as n}from"../types/index.js";function c(t){return async function(r,i){if(!a.includes(r))throw new Error(`unfairly: unknown event "${r}". Allowed: ${a.join(", ")}`);const o=n[r].safeParse(i);if(!o.success)throw new Error(`unfairly: invalid payload for "${r}": ${JSON.stringify(o.error.flatten())}`);return t({method:"POST",path:"/api/sdk/v1/events/emit",body:{event:r,data:o.data}})}}export{a as ALLOWED_EVENT_NAMES,n as EVENT_PAYLOAD_SCHEMAS,c as makeEmit};
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -10,4 +10,3 @@ export type { UnfairlyClient, UnfairlyClientOptions, VaultClient, } from "./clie
|
|
|
10
10
|
export { ALLOWED_EVENT_NAMES, EVENT_PAYLOAD_SCHEMAS, } from "./types/index.js";
|
|
11
11
|
export type { AllowedEventName, EventPayload, CheckpointInput, CheckpointResult, TrustTier, SearchHit, SearchDocumentSummary, SearchResponse, VaultDocument, MeResponse, SdkErrorBody, } from "./types/index.js";
|
|
12
12
|
export { UnfairlyApiError } from "./transport.js";
|
|
13
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/lib/index.js
CHANGED
|
@@ -1,11 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* `unfairly` package library surface.
|
|
3
|
-
*
|
|
4
|
-
* Anything exported here is part of the public API contract. Keep this
|
|
5
|
-
* file curated — internal helpers (transport internals, CLI prompts)
|
|
6
|
-
* are NOT exported even though they live in this package.
|
|
7
|
-
*/
|
|
8
|
-
export { createUnfairlyClient } from "./client.js";
|
|
9
|
-
export { ALLOWED_EVENT_NAMES, EVENT_PAYLOAD_SCHEMAS, } from "./types/index.js";
|
|
10
|
-
export { UnfairlyApiError } from "./transport.js";
|
|
11
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
import{createUnfairlyClient as o}from"./client.js";import{ALLOWED_EVENT_NAMES as A,EVENT_PAYLOAD_SCHEMAS as f}from"./types/index.js";import{UnfairlyApiError as i}from"./transport.js";export{A as ALLOWED_EVENT_NAMES,f as EVENT_PAYLOAD_SCHEMAS,i as UnfairlyApiError,o as createUnfairlyClient};
|
package/dist/lib/transport.d.ts
CHANGED
package/dist/lib/transport.js
CHANGED
|
@@ -1,85 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* HTTP transport for the SDK.
|
|
3
|
-
*
|
|
4
|
-
* Stays intentionally tiny: builds a request, hits the Unfairly REST
|
|
5
|
-
* surface, parses JSON, throws a typed `UnfairlyApiError` on non-2xx.
|
|
6
|
-
*
|
|
7
|
-
* The `fetchImpl` override exists so tests can drop a fake fetch in
|
|
8
|
-
* without monkey-patching globalThis. Don't bake msw in here — keep this
|
|
9
|
-
* runtime-agnostic so the SDK works in Node, Bun, edge runtimes, etc.
|
|
10
|
-
*
|
|
11
|
-
* Token redaction: we never log the bearer token. The shape we log is
|
|
12
|
-
* `{ length, last4 }` only — see `redactToken`.
|
|
13
|
-
*/
|
|
14
|
-
export class UnfairlyApiError extends Error {
|
|
15
|
-
status;
|
|
16
|
-
body;
|
|
17
|
-
constructor(status, body, message) {
|
|
18
|
-
super(message ?? (("error" in body && body.error) || `Request failed (${status})`));
|
|
19
|
-
this.name = "UnfairlyApiError";
|
|
20
|
-
this.status = status;
|
|
21
|
-
this.body = body;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
export function redactToken(token) {
|
|
25
|
-
return {
|
|
26
|
-
length: token.length,
|
|
27
|
-
last4: token.slice(-4),
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
export function createTransport(opts) {
|
|
31
|
-
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
32
|
-
if (!fetchImpl) {
|
|
33
|
-
throw new Error("unfairly: no fetch implementation found. Pass `fetchImpl` or run on Node 18+ / a fetch-capable runtime.");
|
|
34
|
-
}
|
|
35
|
-
const baseUrl = opts.baseUrl.replace(/\/$/, "");
|
|
36
|
-
const timeoutMs = opts.timeoutMs ?? 30_000;
|
|
37
|
-
const userAgent = opts.userAgent ?? "unfairly/0.5.0";
|
|
38
|
-
return async function request(req) {
|
|
39
|
-
const url = new URL(baseUrl + req.path);
|
|
40
|
-
if (req.query) {
|
|
41
|
-
for (const [k, v] of Object.entries(req.query)) {
|
|
42
|
-
if (v === undefined)
|
|
43
|
-
continue;
|
|
44
|
-
url.searchParams.set(k, String(v));
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
const controller = new AbortController();
|
|
48
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
49
|
-
let res;
|
|
50
|
-
try {
|
|
51
|
-
res = await fetchImpl(url.toString(), {
|
|
52
|
-
method: req.method ?? "GET",
|
|
53
|
-
headers: {
|
|
54
|
-
Authorization: `Bearer ${opts.apiKey}`,
|
|
55
|
-
"Content-Type": "application/json",
|
|
56
|
-
Accept: "application/json",
|
|
57
|
-
"User-Agent": userAgent,
|
|
58
|
-
},
|
|
59
|
-
body: req.body === undefined ? undefined : JSON.stringify(req.body),
|
|
60
|
-
signal: controller.signal,
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
finally {
|
|
64
|
-
clearTimeout(timer);
|
|
65
|
-
}
|
|
66
|
-
const text = await res.text();
|
|
67
|
-
let parsed = null;
|
|
68
|
-
if (text) {
|
|
69
|
-
try {
|
|
70
|
-
parsed = JSON.parse(text);
|
|
71
|
-
}
|
|
72
|
-
catch {
|
|
73
|
-
parsed = { raw: text };
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
if (!res.ok) {
|
|
77
|
-
const body = parsed && typeof parsed === "object"
|
|
78
|
-
? parsed
|
|
79
|
-
: { raw: text };
|
|
80
|
-
throw new UnfairlyApiError(res.status, body);
|
|
81
|
-
}
|
|
82
|
-
return parsed;
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
//# sourceMappingURL=transport.js.map
|
|
1
|
+
class d extends Error{status;body;constructor(n,o,s){super(s??("error"in o&&o.error||`Request failed (${n})`)),this.name="UnfairlyApiError",this.status=n,this.body=o}}function m(t){return{length:t.length,last4:t.slice(-4)}}function b(t){const n=t.fetchImpl??globalThis.fetch;if(!n)throw new Error("unfairly: no fetch implementation found. Pass `fetchImpl` or run on Node 18+ / a fetch-capable runtime.");const o=t.baseUrl.replace(/\/$/,""),s=t.timeoutMs??3e4,h=t.userAgent??"unfairly/0.5.0";return async function(e){const l=new URL(o+e.path);if(e.query)for(const[c,f]of Object.entries(e.query))f!==void 0&&l.searchParams.set(c,String(f));const u=new AbortController,p=setTimeout(()=>u.abort(),s);let i;try{i=await n(l.toString(),{method:e.method??"GET",headers:{Authorization:`Bearer ${t.apiKey}`,"Content-Type":"application/json",Accept:"application/json","User-Agent":h},body:e.body===void 0?void 0:JSON.stringify(e.body),signal:u.signal})}finally{clearTimeout(p)}const a=await i.text();let r=null;if(a)try{r=JSON.parse(a)}catch{r={raw:a}}if(!i.ok){const c=r&&typeof r=="object"?r:{raw:a};throw new d(i.status,c)}return r}}export{d as UnfairlyApiError,b as createTransport,m as redactToken};
|
package/dist/lib/types/index.js
CHANGED
|
@@ -1,50 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* SDK shared types.
|
|
3
|
-
*
|
|
4
|
-
* `ALLOWED_EVENT_NAMES` is the CLOSED allowlist of events external callers
|
|
5
|
-
* are allowed to emit via `/api/sdk/v1/events/emit`. The server validates
|
|
6
|
-
* incoming events against this same list and per-event payload schema
|
|
7
|
-
* before forwarding to Inngest. Adding an event here without also adding
|
|
8
|
-
* a schema below + an Inngest function on the server side means the event
|
|
9
|
-
* lands in the queue with nobody listening — keep the three in lockstep.
|
|
10
|
-
*
|
|
11
|
-
* Why a closed list: Codex flagged an earlier draft as an "arbitrary
|
|
12
|
-
* event injection" vector. Anything that's not on this list is rejected
|
|
13
|
-
* with a 400, regardless of token scope.
|
|
14
|
-
*/
|
|
15
|
-
import { z } from "zod";
|
|
16
|
-
export const ALLOWED_EVENT_NAMES = [
|
|
17
|
-
"growth-agent/signal.detected",
|
|
18
|
-
"funding-agent/update.requested",
|
|
19
|
-
"vault/content.landed",
|
|
20
|
-
];
|
|
21
|
-
// Source of truth for the growth-agent signal payload shape.
|
|
22
|
-
const GrowthSignalPayloadSchema = z.object({
|
|
23
|
-
signal_id: z.string().min(1).max(100),
|
|
24
|
-
source: z.enum(["x-listener", "linkedin-listener", "hn-listener", "manual"]),
|
|
25
|
-
trust_tier: z.enum(["gold", "silver", "bronze"]),
|
|
26
|
-
dedupe_key: z.string().min(1).max(200),
|
|
27
|
-
payload: z.object({
|
|
28
|
-
text: z.string().max(5000),
|
|
29
|
-
blocks: z.array(z.unknown()).max(50).optional(),
|
|
30
|
-
url: z.string().url().optional(),
|
|
31
|
-
author: z.string().max(200).optional(),
|
|
32
|
-
}),
|
|
33
|
-
});
|
|
34
|
-
const FundingUpdateRequestedSchema = z.object({
|
|
35
|
-
vault_slug: z.string().min(1).max(120),
|
|
36
|
-
window: z.enum(["7d", "14d", "30d"]).default("7d"),
|
|
37
|
-
reason: z.string().max(500).optional(),
|
|
38
|
-
});
|
|
39
|
-
const VaultContentLandedSchema = z.object({
|
|
40
|
-
vault_slug: z.string().min(1).max(120),
|
|
41
|
-
document_id: z.string().min(1).max(120),
|
|
42
|
-
trust_tier: z.enum(["gold", "silver", "bronze"]),
|
|
43
|
-
source: z.string().max(200).optional(),
|
|
44
|
-
});
|
|
45
|
-
export const EVENT_PAYLOAD_SCHEMAS = {
|
|
46
|
-
"growth-agent/signal.detected": GrowthSignalPayloadSchema,
|
|
47
|
-
"funding-agent/update.requested": FundingUpdateRequestedSchema,
|
|
48
|
-
"vault/content.landed": VaultContentLandedSchema,
|
|
49
|
-
};
|
|
50
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
import{z as t}from"zod";const i=["growth-agent/signal.detected","funding-agent/update.requested","vault/content.landed"],n=t.object({signal_id:t.string().min(1).max(100),source:t.enum(["x-listener","linkedin-listener","hn-listener","manual"]),trust_tier:t.enum(["gold","silver","bronze"]),dedupe_key:t.string().min(1).max(200),payload:t.object({text:t.string().max(5e3),blocks:t.array(t.unknown()).max(50).optional(),url:t.string().url().optional(),author:t.string().max(200).optional()})}),e=t.object({vault_slug:t.string().min(1).max(120),window:t.enum(["7d","14d","30d"]).default("7d"),reason:t.string().max(500).optional()}),a=t.object({vault_slug:t.string().min(1).max(120),document_id:t.string().min(1).max(120),trust_tier:t.enum(["gold","silver","bronze"]),source:t.string().max(200).optional()}),r={"growth-agent/signal.detected":n,"funding-agent/update.requested":e,"vault/content.landed":a};export{i as ALLOWED_EVENT_NAMES,r as EVENT_PAYLOAD_SCHEMAS};
|
|
@@ -9,4 +9,3 @@ import type { CheckpointInput, CheckpointResult } from "../types/index.js";
|
|
|
9
9
|
* and rejected at worst.
|
|
10
10
|
*/
|
|
11
11
|
export declare function makeVaultCheckpoint(request: TransportFn, slug: string): (input: CheckpointInput) => Promise<CheckpointResult>;
|
|
12
|
-
//# sourceMappingURL=checkpoint.d.ts.map
|
|
@@ -1,18 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Save a checkpoint to the vault.
|
|
3
|
-
*
|
|
4
|
-
* `actor_email` and `actor_kind` are intentionally not part of
|
|
5
|
-
* `CheckpointInput`. The server derives identity from the bearer token
|
|
6
|
-
* owner; supplying those fields in the request body is a no-op at best
|
|
7
|
-
* and rejected at worst.
|
|
8
|
-
*/
|
|
9
|
-
export function makeVaultCheckpoint(request, slug) {
|
|
10
|
-
return async function checkpoint(input) {
|
|
11
|
-
return request({
|
|
12
|
-
method: "POST",
|
|
13
|
-
path: `/api/sdk/v1/vault/${encodeURIComponent(slug)}/checkpoint`,
|
|
14
|
-
body: input,
|
|
15
|
-
});
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
//# sourceMappingURL=checkpoint.js.map
|
|
1
|
+
function c(n,t){return async function(e){return n({method:"POST",path:`/api/sdk/v1/vault/${encodeURIComponent(t)}/checkpoint`,body:e})}}export{c as makeVaultCheckpoint};
|
package/dist/lib/vault/read.d.ts
CHANGED
package/dist/lib/vault/read.js
CHANGED
|
@@ -1,9 +1 @@
|
|
|
1
|
-
|
|
2
|
-
return async function readDocument(nameOrSlug) {
|
|
3
|
-
return request({
|
|
4
|
-
method: "GET",
|
|
5
|
-
path: `/api/sdk/v1/vault/${encodeURIComponent(slug)}/documents/${encodeURIComponent(nameOrSlug)}`,
|
|
6
|
-
});
|
|
7
|
-
};
|
|
8
|
-
}
|
|
9
|
-
//# sourceMappingURL=read.js.map
|
|
1
|
+
function a(e,n){return async function(t){return e({method:"GET",path:`/api/sdk/v1/vault/${encodeURIComponent(n)}/documents/${encodeURIComponent(t)}`})}}export{a as makeVaultRead};
|
package/dist/lib/vault/search.js
CHANGED
|
@@ -1,10 +1 @@
|
|
|
1
|
-
|
|
2
|
-
return async function search(query, options = {}) {
|
|
3
|
-
return request({
|
|
4
|
-
method: "POST",
|
|
5
|
-
path: `/api/sdk/v1/vault/${encodeURIComponent(slug)}/search`,
|
|
6
|
-
body: { query, ...options },
|
|
7
|
-
});
|
|
8
|
-
};
|
|
9
|
-
}
|
|
10
|
-
//# sourceMappingURL=search.js.map
|
|
1
|
+
function r(e,n){return async function(t,a={}){return e({method:"POST",path:`/api/sdk/v1/vault/${encodeURIComponent(n)}/search`,body:{query:t,...a}})}}export{r as makeVaultSearch};
|
package/dist/pace/device.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ declare const DeviceStateSchema: z.ZodObject<{
|
|
|
25
25
|
paused: z.ZodOptional<z.ZodBoolean>;
|
|
26
26
|
last_upload_at: z.ZodOptional<z.ZodString>;
|
|
27
27
|
last_session_sweep_at: z.ZodOptional<z.ZodString>;
|
|
28
|
+
history_backfilled_at: z.ZodOptional<z.ZodString>;
|
|
28
29
|
repository_policy_refreshed_at: z.ZodOptional<z.ZodString>;
|
|
29
30
|
collection_policy_version: z.ZodOptional<z.ZodLiteral<"metadata-v3">>;
|
|
30
31
|
managed_files: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
@@ -58,6 +59,7 @@ declare const DeviceStateSchema: z.ZodObject<{
|
|
|
58
59
|
paused?: boolean | undefined;
|
|
59
60
|
last_upload_at?: string | undefined;
|
|
60
61
|
last_session_sweep_at?: string | undefined;
|
|
62
|
+
history_backfilled_at?: string | undefined;
|
|
61
63
|
repository_policy_refreshed_at?: string | undefined;
|
|
62
64
|
managed_files?: string[] | undefined;
|
|
63
65
|
intelligence_install?: {
|
|
@@ -76,6 +78,7 @@ declare const DeviceStateSchema: z.ZodObject<{
|
|
|
76
78
|
paused?: boolean | undefined;
|
|
77
79
|
last_upload_at?: string | undefined;
|
|
78
80
|
last_session_sweep_at?: string | undefined;
|
|
81
|
+
history_backfilled_at?: string | undefined;
|
|
79
82
|
repository_policy_refreshed_at?: string | undefined;
|
|
80
83
|
managed_files?: string[] | undefined;
|
|
81
84
|
intelligence_install?: {
|
|
@@ -98,4 +101,3 @@ export declare function currentDevicePlatform(): {
|
|
|
98
101
|
};
|
|
99
102
|
export declare function needsIntelligenceInstall(state: PaceDeviceState, clients: PaceClientCoverage[]): boolean;
|
|
100
103
|
export {};
|
|
101
|
-
//# sourceMappingURL=device.d.ts.map
|
package/dist/pace/device.js
CHANGED
|
@@ -1,148 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import fs from "node:fs/promises";
|
|
4
|
-
import os from "node:os";
|
|
5
|
-
import path from "node:path";
|
|
6
|
-
import { z } from "zod";
|
|
7
|
-
export const PaceClientIdSchema = z.enum([
|
|
8
|
-
"codex",
|
|
9
|
-
"claude_code",
|
|
10
|
-
"cursor",
|
|
11
|
-
"claude_desktop",
|
|
12
|
-
"gemini_cli",
|
|
13
|
-
"openrouter",
|
|
14
|
-
"chatgpt_desktop",
|
|
15
|
-
]);
|
|
16
|
-
export const PaceClientCoverageSchema = z.object({
|
|
17
|
-
client: PaceClientIdSchema,
|
|
18
|
-
installed: z.boolean(),
|
|
19
|
-
configured: z.boolean(),
|
|
20
|
-
version: z.string().max(200).optional(),
|
|
21
|
-
}).strict();
|
|
22
|
-
const IntelligenceInstallSchema = z.object({
|
|
23
|
-
version: z.string().min(1).max(100),
|
|
24
|
-
runtime_entrypoint: z.string().min(1),
|
|
25
|
-
marketplace_root: z.string().min(1),
|
|
26
|
-
owned_paths: z.array(z.string().min(1)).max(20),
|
|
27
|
-
activated_clients: z.array(PaceClientIdSchema).max(10),
|
|
28
|
-
installed_at: z.string().datetime(),
|
|
29
|
-
}).strict();
|
|
30
|
-
const DeviceStateSchema = z.object({
|
|
31
|
-
installation_id: z.string().uuid(),
|
|
32
|
-
attestation: z.string().min(1).optional(),
|
|
33
|
-
attestation_expires_at: z.string().datetime().optional(),
|
|
34
|
-
paused: z.boolean().optional(),
|
|
35
|
-
last_upload_at: z.string().datetime().optional(),
|
|
36
|
-
last_session_sweep_at: z.string().datetime().optional(),
|
|
37
|
-
repository_policy_refreshed_at: z.string().datetime().optional(),
|
|
38
|
-
collection_policy_version: z.literal("metadata-v3").optional(),
|
|
39
|
-
managed_files: z.array(z.string().min(1)).max(20).optional(),
|
|
40
|
-
intelligence_install: IntelligenceInstallSchema.optional(),
|
|
41
|
-
}).strict();
|
|
42
|
-
export function paceDevicePath() {
|
|
43
|
-
return process.env.UNFAIRLY_PACE_DEVICE_STATE ?? path.join(os.homedir(), ".unfairly", "pace", "device.json");
|
|
44
|
-
}
|
|
45
|
-
export async function readOrCreatePaceDevice() {
|
|
46
|
-
const file = paceDevicePath();
|
|
47
|
-
try {
|
|
48
|
-
return DeviceStateSchema.parse(JSON.parse(await fs.readFile(file, "utf8")));
|
|
49
|
-
}
|
|
50
|
-
catch (error) {
|
|
51
|
-
if (error.code !== "ENOENT" && error instanceof SyntaxError)
|
|
52
|
-
throw error;
|
|
53
|
-
}
|
|
54
|
-
const state = { installation_id: randomUUID() };
|
|
55
|
-
await writePaceDevice(state);
|
|
56
|
-
return state;
|
|
57
|
-
}
|
|
58
|
-
export async function writePaceDevice(state) {
|
|
59
|
-
const parsed = DeviceStateSchema.parse(state);
|
|
60
|
-
const file = paceDevicePath();
|
|
61
|
-
await fs.mkdir(path.dirname(file), { recursive: true, mode: 0o700 });
|
|
62
|
-
await fs.writeFile(file, `${JSON.stringify(parsed, null, 2)}\n`, { encoding: "utf8", mode: 0o600 });
|
|
63
|
-
await fs.chmod(file, 0o600).catch(() => undefined);
|
|
64
|
-
}
|
|
65
|
-
function binaryVersion(binary) {
|
|
66
|
-
const result = spawnSync(binary, ["--version"], { encoding: "utf8", timeout: 2_000 });
|
|
67
|
-
if (result.error || result.status !== 0)
|
|
68
|
-
return { installed: false };
|
|
69
|
-
const version = `${result.stdout || result.stderr}`.trim().slice(0, 200);
|
|
70
|
-
return { installed: true, version: version || undefined };
|
|
71
|
-
}
|
|
72
|
-
async function exists(file) {
|
|
73
|
-
try {
|
|
74
|
-
await fs.access(file);
|
|
75
|
-
return true;
|
|
76
|
-
}
|
|
77
|
-
catch {
|
|
78
|
-
return false;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
export async function detectPaceClients() {
|
|
82
|
-
const home = os.homedir();
|
|
83
|
-
const codex = binaryVersion("codex");
|
|
84
|
-
const claude = binaryVersion("claude");
|
|
85
|
-
const gemini = binaryVersion("gemini");
|
|
86
|
-
const cursorCli = binaryVersion("cursor");
|
|
87
|
-
const openrouterConfigured = Boolean(process.env.OPENROUTER_API_KEY);
|
|
88
|
-
const claudeDesktopPath = process.platform === "darwin"
|
|
89
|
-
? "/Applications/Claude.app"
|
|
90
|
-
: path.join(process.env.APPDATA ?? home, "Claude");
|
|
91
|
-
const chatgptDesktopPath = process.platform === "darwin"
|
|
92
|
-
? "/Applications/ChatGPT.app"
|
|
93
|
-
: path.join(process.env.LOCALAPPDATA ?? home, "Programs", "ChatGPT");
|
|
94
|
-
const cursorAppPath = process.platform === "darwin"
|
|
95
|
-
? "/Applications/Cursor.app"
|
|
96
|
-
: path.join(process.env.LOCALAPPDATA ?? home, "Programs", "cursor");
|
|
97
|
-
return [
|
|
98
|
-
{
|
|
99
|
-
client: "codex",
|
|
100
|
-
...codex,
|
|
101
|
-
configured: codex.installed && await exists(path.join(home, ".codex", "config.toml")),
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
client: "claude_code",
|
|
105
|
-
...claude,
|
|
106
|
-
configured: claude.installed && await exists(path.join(home, ".claude.json")),
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
client: "cursor",
|
|
110
|
-
installed: cursorCli.installed || await exists(cursorAppPath),
|
|
111
|
-
configured: await exists(path.join(home, ".cursor", "hooks.json")) || await exists(path.join(home, ".claude", "settings.json")),
|
|
112
|
-
version: cursorCli.version,
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
client: "claude_desktop",
|
|
116
|
-
installed: await exists(claudeDesktopPath),
|
|
117
|
-
configured: await exists(process.platform === "darwin"
|
|
118
|
-
? path.join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json")
|
|
119
|
-
: path.join(process.env.APPDATA ?? home, "Claude", "claude_desktop_config.json")),
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
client: "gemini_cli",
|
|
123
|
-
...gemini,
|
|
124
|
-
configured: gemini.installed && await exists(path.join(home, ".gemini", "settings.json")),
|
|
125
|
-
},
|
|
126
|
-
{
|
|
127
|
-
client: "openrouter",
|
|
128
|
-
installed: openrouterConfigured,
|
|
129
|
-
configured: openrouterConfigured,
|
|
130
|
-
},
|
|
131
|
-
{
|
|
132
|
-
client: "chatgpt_desktop",
|
|
133
|
-
installed: await exists(chatgptDesktopPath),
|
|
134
|
-
configured: false,
|
|
135
|
-
},
|
|
136
|
-
].map((client) => PaceClientCoverageSchema.parse(client));
|
|
137
|
-
}
|
|
138
|
-
export function currentDevicePlatform() {
|
|
139
|
-
return { platform: process.platform, arch: process.arch };
|
|
140
|
-
}
|
|
141
|
-
export function needsIntelligenceInstall(state, clients) {
|
|
142
|
-
if (!state.intelligence_install)
|
|
143
|
-
return true;
|
|
144
|
-
const hookClients = new Set(["codex", "claude_code", "cursor", "gemini_cli"]);
|
|
145
|
-
const activated = new Set(state.intelligence_install.activated_clients);
|
|
146
|
-
return clients.some((client) => client.installed && hookClients.has(client.client) && !activated.has(client.client));
|
|
147
|
-
}
|
|
148
|
-
//# sourceMappingURL=device.js.map
|
|
1
|
+
import{randomUUID as w}from"node:crypto";import{spawnSync as P}from"node:child_process";import s from"node:fs/promises";import p from"node:os";import o from"node:path";import{z as e}from"zod";const u=e.enum(["codex","claude_code","cursor","claude_desktop","gemini_cli","openrouter","chatgpt_desktop"]),A=e.object({client:u,installed:e.boolean(),configured:e.boolean(),version:e.string().max(200).optional()}).strict(),x=e.object({version:e.string().min(1).max(100),runtime_entrypoint:e.string().min(1),marketplace_root:e.string().min(1),owned_paths:e.array(e.string().min(1)).max(20),activated_clients:e.array(u).max(10),installed_at:e.string().datetime()}).strict(),m=e.object({installation_id:e.string().uuid(),attestation:e.string().min(1).optional(),attestation_expires_at:e.string().datetime().optional(),paused:e.boolean().optional(),last_upload_at:e.string().datetime().optional(),last_session_sweep_at:e.string().datetime().optional(),history_backfilled_at:e.string().datetime().optional(),repository_policy_refreshed_at:e.string().datetime().optional(),collection_policy_version:e.literal("metadata-v3").optional(),managed_files:e.array(e.string().min(1)).max(20).optional(),intelligence_install:x.optional()}).strict();function f(){return process.env.UNFAIRLY_PACE_DEVICE_STATE??o.join(p.homedir(),".unfairly","pace","device.json")}async function T(){const t=f();try{return m.parse(JSON.parse(await s.readFile(t,"utf8")))}catch(i){if(i.code!=="ENOENT"&&i instanceof SyntaxError)throw i}const n={installation_id:w()};return await j(n),n}async function j(t){const n=m.parse(t),i=f();await s.mkdir(o.dirname(i),{recursive:!0,mode:448}),await s.writeFile(i,`${JSON.stringify(n,null,2)}
|
|
2
|
+
`,{encoding:"utf8",mode:384}),await s.chmod(i,384).catch(()=>{})}function l(t){const n=P(t,["--version"],{encoding:"utf8",timeout:2e3});return n.error||n.status!==0?{installed:!1}:{installed:!0,version:`${n.stdout||n.stderr}`.trim().slice(0,200)||void 0}}async function a(t){try{return await s.access(t),!0}catch{return!1}}async function b(){const t=p.homedir(),n=l("codex"),i=l("claude"),c=l("gemini"),r=l("cursor"),d=!!process.env.OPENROUTER_API_KEY,g=process.platform==="darwin"?"/Applications/Claude.app":o.join(process.env.APPDATA??t,"Claude"),_=process.platform==="darwin"?"/Applications/ChatGPT.app":o.join(process.env.LOCALAPPDATA??t,"Programs","ChatGPT"),h=process.platform==="darwin"?"/Applications/Cursor.app":o.join(process.env.LOCALAPPDATA??t,"Programs","cursor");return[{client:"codex",...n,configured:n.installed&&await a(o.join(t,".codex","config.toml"))},{client:"claude_code",...i,configured:i.installed&&await a(o.join(t,".claude.json"))},{client:"cursor",installed:r.installed||await a(h),configured:await a(o.join(t,".cursor","hooks.json"))||await a(o.join(t,".claude","settings.json")),version:r.version},{client:"claude_desktop",installed:await a(g),configured:await a(process.platform==="darwin"?o.join(t,"Library","Application Support","Claude","claude_desktop_config.json"):o.join(process.env.APPDATA??t,"Claude","claude_desktop_config.json"))},{client:"gemini_cli",...c,configured:c.installed&&await a(o.join(t,".gemini","settings.json"))},{client:"openrouter",installed:d,configured:d},{client:"chatgpt_desktop",installed:await a(_),configured:!1}].map(v=>A.parse(v))}function I(){return{platform:process.platform,arch:process.arch}}function O(t,n){if(!t.intelligence_install)return!0;const i=new Set(["codex","claude_code","cursor","gemini_cli"]),c=new Set(t.intelligence_install.activated_clients);return n.some(r=>r.installed&&i.has(r.client)&&!c.has(r.client))}export{A as PaceClientCoverageSchema,u as PaceClientIdSchema,I as currentDevicePlatform,b as detectPaceClients,O as needsIntelligenceInstall,f as paceDevicePath,T as readOrCreatePaceDevice,j as writePaceDevice};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* No-terminal connection for the plugin. On a session start without a
|
|
4
|
+
* collector credential, the plugin starts (or continues) a browser-approved
|
|
5
|
+
* enrollment and hands the person a link. Once approved, it claims a
|
|
6
|
+
* credential bound to this installation. Only these two small files are kept.
|
|
7
|
+
*/
|
|
8
|
+
declare const CredentialSchema: z.ZodObject<{
|
|
9
|
+
installation_id: z.ZodString;
|
|
10
|
+
secret: z.ZodString;
|
|
11
|
+
org_id: z.ZodString;
|
|
12
|
+
}, "strict", z.ZodTypeAny, {
|
|
13
|
+
installation_id: string;
|
|
14
|
+
secret: string;
|
|
15
|
+
org_id: string;
|
|
16
|
+
}, {
|
|
17
|
+
installation_id: string;
|
|
18
|
+
secret: string;
|
|
19
|
+
org_id: string;
|
|
20
|
+
}>;
|
|
21
|
+
export type CollectorCredential = z.infer<typeof CredentialSchema>;
|
|
22
|
+
export declare const collectorCredentialPath: () => string;
|
|
23
|
+
export declare const readCollectorCredential: () => Promise<{
|
|
24
|
+
installation_id: string;
|
|
25
|
+
secret: string;
|
|
26
|
+
org_id: string;
|
|
27
|
+
} | null>;
|
|
28
|
+
export declare function collectorAuthorization(credential: CollectorCredential): string;
|
|
29
|
+
export type EnrollmentState = {
|
|
30
|
+
status: "connected";
|
|
31
|
+
orgId: string;
|
|
32
|
+
} | {
|
|
33
|
+
status: "waiting";
|
|
34
|
+
link: string;
|
|
35
|
+
code: string;
|
|
36
|
+
} | {
|
|
37
|
+
status: "unavailable";
|
|
38
|
+
};
|
|
39
|
+
/** One step of the enrollment state machine; safe to call on every session start. */
|
|
40
|
+
export declare function ensureEnrolled(input: {
|
|
41
|
+
apiUrl: string;
|
|
42
|
+
installationId: string;
|
|
43
|
+
platform: "darwin" | "linux" | "win32";
|
|
44
|
+
arch: "x64" | "arm64";
|
|
45
|
+
clients: string[];
|
|
46
|
+
orgHint?: string;
|
|
47
|
+
fetchImpl?: typeof fetch;
|
|
48
|
+
now?: Date;
|
|
49
|
+
}): Promise<EnrollmentState>;
|
|
50
|
+
/**
|
|
51
|
+
* Checks the enrollment this machine is waiting on, without starting a new
|
|
52
|
+
* one. Claims and stores the credential when the person has approved it.
|
|
53
|
+
*/
|
|
54
|
+
export declare function pollPendingEnrollment(input: {
|
|
55
|
+
apiUrl: string;
|
|
56
|
+
fetchImpl?: typeof fetch;
|
|
57
|
+
now?: Date;
|
|
58
|
+
}): Promise<EnrollmentState | {
|
|
59
|
+
status: "none";
|
|
60
|
+
}>;
|
|
61
|
+
/**
|
|
62
|
+
* Keeps polling after the connect link is shown, so approving in the browser
|
|
63
|
+
* connects this machine within seconds instead of at the next session start.
|
|
64
|
+
* Stops when connected, when the enrollment ends, or at the deadline.
|
|
65
|
+
*/
|
|
66
|
+
export declare function awaitApproval(input: {
|
|
67
|
+
apiUrl: string;
|
|
68
|
+
intervalMs?: number;
|
|
69
|
+
deadlineMs?: number;
|
|
70
|
+
fetchImpl?: typeof fetch;
|
|
71
|
+
sleep?: (ms: number) => Promise<void>;
|
|
72
|
+
clock?: () => number;
|
|
73
|
+
}): Promise<boolean>;
|
|
74
|
+
/** At most one background poller per machine: sessions often start in bursts. */
|
|
75
|
+
export declare function acquireApprovalLock(now?: number): Promise<boolean>;
|
|
76
|
+
export declare const releaseApprovalLock: () => Promise<void | undefined>;
|
|
77
|
+
/** What a SessionStart hook prints: a visible message for the person plus context so the assistant can repeat the link. */
|
|
78
|
+
export declare function sessionStartOutput(state: EnrollmentState, hookEventName?: string): string;
|
|
79
|
+
export {};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import c from"node:fs/promises";import x from"node:os";import l from"node:path";import{z as a}from"zod";const f=a.object({installation_id:a.string().uuid(),secret:a.string().regex(/^[A-Za-z0-9_-]{43}$/),org_id:a.string().uuid()}).strict(),S=a.object({device_code:a.string(),user_code:a.string(),verification_uri:a.string().url(),expires_at:a.string()}).strict(),g=()=>l.join(x.homedir(),".unfairly","pace"),_=()=>process.env.UNFAIRLY_PACE_COLLECTOR??l.join(g(),"collector.json"),d=()=>process.env.UNFAIRLY_PACE_ENROLLMENT??l.join(g(),"enrollment.json");async function m(e,n){try{const t=n.safeParse(JSON.parse(await c.readFile(e,"utf8")));return t.success?t.data:null}catch{return null}}async function u(e,n){await c.mkdir(l.dirname(e),{recursive:!0,mode:448}),await c.writeFile(e,`${JSON.stringify(n)}
|
|
2
|
+
`,{encoding:"utf8",mode:384})}const h=()=>m(_(),f);function C(e){return`Collector ${e.installation_id}.${e.secret}`}async function P(e){const n=await h();if(n)return{status:"connected",orgId:n.org_id};const t=e.fetchImpl??fetch,r=e.now??new Date,i=await w({apiUrl:e.apiUrl,fetchImpl:t,now:r});if(i.status==="connected"||i.status==="waiting")return i;const o=e.clients.filter(v=>["codex","claude_code","cursor","gemini_cli"].includes(v)),p=await t(`${e.apiUrl}/api/ai-pace/enroll`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({installation_id:e.installationId,platform:e.platform,arch:e.arch,clients:o,...e.orgHint?{org_hint:e.orgHint}:{}})});if(!p.ok)return{status:"unavailable"};const s=await p.json();return await u(d(),{device_code:s.device_code,user_code:s.user_code,verification_uri:s.verification_uri,expires_at:new Date(r.getTime()+s.expires_in*1e3).toISOString()}),{status:"waiting",link:s.verification_uri,code:s.user_code}}async function w(e){const n=await h();if(n)return{status:"connected",orgId:n.org_id};const t=await m(d(),S);if(!t||Date.parse(t.expires_at)<=(e.now??new Date).getTime())return{status:"none"};const o=await(await(e.fetchImpl??fetch)(`${e.apiUrl}/api/ai-pace/enroll/poll`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({device_code:t.device_code})})).json().catch(()=>({}));return o.status==="approved"&&o.installation_id&&o.secret&&o.org_id?(await u(_(),f.parse({installation_id:o.installation_id,secret:o.secret,org_id:o.org_id})),await c.unlink(d()).catch(()=>{}),{status:"connected",orgId:o.org_id}):o.status==="pending"?{status:"waiting",link:t.verification_uri,code:t.user_code}:{status:"none"}}async function A(e){const n=e.clock??Date.now,t=e.sleep??(i=>new Promise(o=>setTimeout(o,i))),r=n()+(e.deadlineMs??16*6e4);for(;n()<r;){const i=await w({apiUrl:e.apiUrl,fetchImpl:e.fetchImpl,now:new Date(n())}).catch(()=>({status:"waiting"}));if(i.status==="connected")return!0;if(i.status==="none")return!1;await t(e.intervalMs??5e3)}return!1}const y=()=>l.join(l.dirname(d()),"approval-wait.json");async function N(e=Date.now()){const n=y();try{const t=JSON.parse(await c.readFile(n,"utf8")),r=typeof t.started_at=="number"&&e-t.started_at<17*6e4;let i=!1;try{typeof t.pid=="number"&&(process.kill(t.pid,0),i=!0)}catch{i=!1}if(r&&i)return!1}catch{}return await u(n,{pid:process.pid,started_at:e}),!0}const T=()=>c.unlink(y()).catch(()=>{});function U(e,n="SessionStart"){if(e.status!=="waiting")return"";const t=`Connect Unfairly Intelligence to your team: open ${e.link} and approve code ${e.code}. It shares session metadata only, never prompts or code.`;return JSON.stringify({systemMessage:t,hookSpecificOutput:{hookEventName:n,additionalContext:`The Unfairly Intelligence plugin is installed but this machine is not connected yet. At a natural point, tell the user once: "${t}" Do not repeat it after they connect.`}})}export{N as acquireApprovalLock,A as awaitApproval,C as collectorAuthorization,_ as collectorCredentialPath,P as ensureEnrolled,w as pollPendingEnrollment,h as readCollectorCredential,T as releaseApprovalLock,U as sessionStartOutput};
|
package/dist/pace/identity.d.ts
CHANGED
package/dist/pace/identity.js
CHANGED
|
@@ -1,17 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
/**
|
|
3
|
-
* Produces a stable, opaque UUID for one AI workflow without exposing the raw
|
|
4
|
-
* installation or session identifiers in downstream joins.
|
|
5
|
-
*/
|
|
6
|
-
export function deterministicWorkflowId(input) {
|
|
7
|
-
const bytes = createHash("sha256")
|
|
8
|
-
.update(`${input.installationId}\u0000${input.source}\u0000${input.sessionId}`, "utf8")
|
|
9
|
-
.digest()
|
|
10
|
-
.subarray(0, 16);
|
|
11
|
-
// Mark the deterministic hash as a name-based UUID and set the RFC variant.
|
|
12
|
-
bytes[6] = (bytes[6] & 0x0f) | 0x50;
|
|
13
|
-
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
14
|
-
const hex = bytes.toString("hex");
|
|
15
|
-
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
16
|
-
}
|
|
17
|
-
//# sourceMappingURL=identity.js.map
|
|
1
|
+
import{createHash as i}from"node:crypto";function r(t){const e=i("sha256").update(`${t.installationId}\0${t.source}\0${t.sessionId}`,"utf8").digest().subarray(0,16);e[6]=e[6]&15|80,e[8]=e[8]&63|128;const s=e.toString("hex");return`${s.slice(0,8)}-${s.slice(8,12)}-${s.slice(12,16)}-${s.slice(16,20)}-${s.slice(20)}`}export{r as deterministicWorkflowId};
|
package/dist/pace/install.d.ts
CHANGED