@peektag-ai/cli 0.1.0 → 0.1.2
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/README.md +43 -1
- package/dist/auth.d.ts +1 -3
- package/dist/auth.js +37 -33
- package/dist/auth.js.map +1 -1
- package/dist/browser.d.ts +5 -0
- package/dist/browser.js +16 -0
- package/dist/browser.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/credential-store.d.ts +10 -0
- package/dist/credential-store.js +98 -0
- package/dist/credential-store.js.map +1 -0
- package/dist/installer.d.ts +9 -0
- package/dist/installer.js +37 -6
- package/dist/installer.js.map +1 -1
- package/dist/mcp.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,9 +8,37 @@ Node.js 20 or newer is required.
|
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
10
|
npm install -g @peektag-ai/cli
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The public npm package is [@peektag-ai/cli](https://www.npmjs.com/package/@peektag-ai/cli). Its source lives in this repository at `tools/peektag-cli`; the server repository is not a public source download.
|
|
14
|
+
|
|
15
|
+
### Connect an existing coding client
|
|
16
|
+
|
|
17
|
+
Install Cursor, Claude Code or Codex first, then run the matching command:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
peektag mcp install cursor
|
|
21
|
+
peektag mcp install claude-code
|
|
22
|
+
peektag mcp install codex
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Use CLI 0.1.2 or newer. These installers add the public remote MCP URL to the client's user configuration. Cursor and Codex use dedicated public OAuth client IDs for the production endpoint, with no client secret. Custom/local endpoints retain their own authentication configuration. The installers do not install the coding client or share the CLI's credentials with it. Complete authorization in the client:
|
|
26
|
+
|
|
27
|
+
- Cursor: restart the app, open Customize → MCP, enable `peektag` and sign in.
|
|
28
|
+
- Claude Code: open `/mcp`, select `peektag` and sign in.
|
|
29
|
+
- Codex: adding the server may open sign-in automatically. For explicit sign-in or reconnection, run `codex mcp login peektag --scopes peektag.mcp,offline_access`, then restart the session. Use an up-to-date Codex version supporting `--oauth-client-id`.
|
|
30
|
+
|
|
31
|
+
Verify the client can list PeekTag experience templates before creating or editing an experience. Each host uses the existing PeekTag MCP tools and native agents; this CLI does not implement a separate agent.
|
|
32
|
+
|
|
33
|
+
### Use standalone CLI commands
|
|
34
|
+
|
|
35
|
+
```bash
|
|
11
36
|
peektag auth login
|
|
37
|
+
peektag mcp tools
|
|
12
38
|
```
|
|
13
39
|
|
|
40
|
+
This sign-in is separate from the coding client's authorization. It requires the configured public Keycloak client described below. The default endpoint is production; use the non-secret environment overrides below for local development.
|
|
41
|
+
|
|
14
42
|
For local development:
|
|
15
43
|
|
|
16
44
|
```bash
|
|
@@ -54,7 +82,9 @@ Defaults:
|
|
|
54
82
|
|
|
55
83
|
Use `peektag config show` and `peektag config set`. Environment overrides are `PEEKTAG_MCP_URL`, `PEEKTAG_AUTHORITY`, `PEEKTAG_OAUTH_CLIENT_ID`, and `PEEKTAG_OAUTH_SCOPE`. Only non-secret configuration is written to the config file.
|
|
56
84
|
|
|
57
|
-
The Keycloak realm must contain a public `peektag-cli` client with Standard Flow and PKCE S256 enabled.
|
|
85
|
+
The Keycloak realm must contain a public `peektag-cli` client with Standard Flow and PKCE S256 enabled. Register `http://127.0.0.1/callback`; Keycloak accepts the ephemeral loopback port under RFC 8252. Do not register an unsupported port wildcard. Map the `peektag.mcp` scope into access tokens and include the API's accepted audience. Keep Direct Access Grants, implicit flow, service accounts and client authentication disabled. The maintained client manifest and fail-closed provisioning command are in `infra/aws/keycloak` and `infra/aws/scripts/provision-native-mcp-oauth.ps1` in the server repository.
|
|
86
|
+
|
|
87
|
+
Tokens are held only in the OS credential store. Version 0.1.2 splits the token bundle into bounded entries and publishes a manifest only after all entries are stored, avoiding the Windows single-entry size limit. Legacy single-entry credentials remain readable and migrate on refresh. After signing in with 0.1.2, keep using 0.1.2 or newer; 0.1.1 cannot read the chunked format.
|
|
58
88
|
|
|
59
89
|
## Safety
|
|
60
90
|
|
|
@@ -67,3 +97,15 @@ npm run check
|
|
|
67
97
|
npm test
|
|
68
98
|
npm pack --dry-run
|
|
69
99
|
```
|
|
100
|
+
|
|
101
|
+
## 0.1.2 — Native OAuth and Windows credentials (2026-10-19)
|
|
102
|
+
|
|
103
|
+
Real testing of 0.1.1 found a missing production CLI client, rejected Codex dynamic registration and a Windows keychain size failure with real Keycloak tokens. This patch adds bounded keychain storage, public pre-registered Cursor/Codex client configuration, safe Cursor configuration migration and explicit revocation failures. The browser callback now asks users to confirm completion in the terminal rather than reporting success before credentials are saved.
|
|
104
|
+
|
|
105
|
+
The production CLI and Codex clients were provisioned with PKCE S256, consent and restricted callbacks without relaxing dynamic registration policies. Live checks verified standalone sign-in, a protected profile call, template listing, refresh, revocation rejection and reconnection. Native Codex app-server testing used an ephemeral session with only PeekTag configured and directly called `peektag_profile`; no model invocation was required. Cursor tool discovery alone is not proof of authenticated tool execution; complete and verify that host's login separately.
|
|
106
|
+
|
|
107
|
+
## 0.1.1 — Onboarding corrections (2026-10-19)
|
|
108
|
+
|
|
109
|
+
This patch launches Windows sign-in without passing the authorization query through `cmd /c start`, handles browser spawn failures, validates callback method/path and state bytes, ignores unrelated callbacks, and clears the callback timer when login ends.
|
|
110
|
+
|
|
111
|
+
Verification includes the TypeScript check and 10 tests covering argument handling, configuration, browser launch arguments, PKCE callback rejection and cleanup. The published `0.1.0` package was separately installed into an isolated directory and exercised against a local MCP fixture: initialization, tool listing, calling `peektag_answer`, large string IDs, all three installers, existing Cursor configuration preservation, and invalid input. Codex and Claude Code installers used recording stubs rather than changing real client settings. Actual end-user OAuth sign-in, refresh and revocation against production remain separate release checks; the local callback tests do not prove those completed.
|
package/dist/auth.d.ts
CHANGED
|
@@ -7,8 +7,6 @@ export interface StoredTokens {
|
|
|
7
7
|
}
|
|
8
8
|
export declare function readStoredTokens(config: CliConfig): Promise<StoredTokens | undefined>;
|
|
9
9
|
export declare function getAccessToken(config: CliConfig): Promise<string>;
|
|
10
|
-
declare function
|
|
11
|
-
export declare function login(config: CliConfig, open?: typeof openBrowser): Promise<StoredTokens>;
|
|
10
|
+
export declare function login(config: CliConfig, open?: (url: string) => void | Promise<void>): Promise<StoredTokens>;
|
|
12
11
|
export declare function logout(config: CliConfig): Promise<boolean>;
|
|
13
12
|
export declare function tokenIdentity(accessToken: string): Record<string, unknown>;
|
|
14
|
-
export {};
|
package/dist/auth.js
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
|
|
2
2
|
import { createServer } from "node:http";
|
|
3
|
-
import {
|
|
3
|
+
import { openSignInBrowser } from "./browser.js";
|
|
4
4
|
import { AsyncEntry } from "@napi-rs/keyring";
|
|
5
5
|
import { assertHttpsOrLoopback } from "./config.js";
|
|
6
|
+
import { deleteCredential, readCredential, writeCredential } from "./credential-store.js";
|
|
6
7
|
const KEYRING_SERVICE = "com.peektag.cli";
|
|
7
8
|
const CALLBACK_TIMEOUT_MS = 180_000;
|
|
9
|
+
const OAUTH_REQUEST_TIMEOUT_MS = 30_000;
|
|
8
10
|
function keyring(config) {
|
|
9
|
-
return new AsyncEntry(KEYRING_SERVICE, `${config.authority}|${config.clientId}`);
|
|
11
|
+
return suffix => new AsyncEntry(KEYRING_SERVICE, `${config.authority}|${config.clientId}${suffix}`);
|
|
10
12
|
}
|
|
11
13
|
async function discover(config) {
|
|
12
14
|
const authority = assertHttpsOrLoopback(config.authority, "OAuth authority");
|
|
13
15
|
const discoveryUrl = new URL(`${authority.pathname.replace(/\/$/, "")}/.well-known/openid-configuration`, authority);
|
|
14
|
-
const response = await fetch(discoveryUrl, { headers: { Accept: "application/json" } });
|
|
16
|
+
const response = await fetch(discoveryUrl, { headers: { Accept: "application/json" }, signal: AbortSignal.timeout(OAUTH_REQUEST_TIMEOUT_MS) });
|
|
15
17
|
if (!response.ok)
|
|
16
18
|
throw new Error(`OAuth discovery failed (${response.status}).`);
|
|
17
19
|
const metadata = await response.json();
|
|
@@ -30,7 +32,7 @@ function toStoredTokens(response, previousRefreshToken) {
|
|
|
30
32
|
}
|
|
31
33
|
async function persist(config, tokens) {
|
|
32
34
|
try {
|
|
33
|
-
await keyring(config)
|
|
35
|
+
await writeCredential(keyring(config), JSON.stringify(tokens));
|
|
34
36
|
}
|
|
35
37
|
catch (error) {
|
|
36
38
|
throw new Error(`Could not store credentials in the operating-system keychain: ${error.message}`);
|
|
@@ -38,7 +40,7 @@ async function persist(config, tokens) {
|
|
|
38
40
|
}
|
|
39
41
|
export async function readStoredTokens(config) {
|
|
40
42
|
try {
|
|
41
|
-
const value = await keyring(config)
|
|
43
|
+
const value = await readCredential(keyring(config));
|
|
42
44
|
return value ? JSON.parse(value) : undefined;
|
|
43
45
|
}
|
|
44
46
|
catch (error) {
|
|
@@ -52,6 +54,7 @@ async function tokenRequest(endpoint, fields) {
|
|
|
52
54
|
method: "POST",
|
|
53
55
|
headers: { Accept: "application/json", "Content-Type": "application/x-www-form-urlencoded" },
|
|
54
56
|
body: new URLSearchParams(fields),
|
|
57
|
+
signal: AbortSignal.timeout(OAUTH_REQUEST_TIMEOUT_MS),
|
|
55
58
|
});
|
|
56
59
|
const body = await response.json().catch(() => ({}));
|
|
57
60
|
if (!response.ok) {
|
|
@@ -88,13 +91,7 @@ export async function getAccessToken(config) {
|
|
|
88
91
|
function base64Url(bytes) {
|
|
89
92
|
return bytes.toString("base64url");
|
|
90
93
|
}
|
|
91
|
-
function
|
|
92
|
-
const command = process.platform === "win32" ? "cmd" : process.platform === "darwin" ? "open" : "xdg-open";
|
|
93
|
-
const args = process.platform === "win32" ? ["/c", "start", "", url] : [url];
|
|
94
|
-
const child = spawn(command, args, { detached: true, stdio: "ignore", windowsHide: true });
|
|
95
|
-
child.unref();
|
|
96
|
-
}
|
|
97
|
-
export async function login(config, open = openBrowser) {
|
|
94
|
+
export async function login(config, open = openSignInBrowser) {
|
|
98
95
|
const metadata = await discover(config);
|
|
99
96
|
const verifier = base64Url(randomBytes(48));
|
|
100
97
|
const challenge = base64Url(createHash("sha256").update(verifier).digest());
|
|
@@ -111,25 +108,30 @@ export async function login(config, open = openBrowser) {
|
|
|
111
108
|
const code = new Promise((res, rej) => { settle = res; fail = rej; });
|
|
112
109
|
const timer = setTimeout(() => fail(new Error("OAuth login timed out.")), CALLBACK_TIMEOUT_MS);
|
|
113
110
|
server.on("request", (request, response) => {
|
|
114
|
-
const url = new URL(request.url ?? "/",
|
|
111
|
+
const url = new URL(request.url ?? "/", "http://127.0.0.1");
|
|
115
112
|
const state = url.searchParams.get("state") ?? "";
|
|
116
|
-
const
|
|
113
|
+
const receivedState = Buffer.from(state);
|
|
114
|
+
const expectedStateBytes = Buffer.from(expectedState);
|
|
115
|
+
const stateMatches = receivedState.length === expectedStateBytes.length && timingSafeEqual(receivedState, expectedStateBytes);
|
|
116
|
+
if (request.method !== "GET" || url.pathname !== "/callback" || !stateMatches) {
|
|
117
|
+
response.writeHead(400, { "Content-Type": "text/plain; charset=utf-8", "Cache-Control": "no-store" });
|
|
118
|
+
response.end("Invalid sign-in callback.");
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
117
121
|
const error = url.searchParams.get("error_description") ?? url.searchParams.get("error");
|
|
118
122
|
const authorizationCode = url.searchParams.get("code");
|
|
119
123
|
const success = stateMatches && !error && authorizationCode;
|
|
120
124
|
response.writeHead(success ? 200 : 400, { "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-store" });
|
|
121
|
-
response.end(success ? "<h1>PeekTag
|
|
125
|
+
response.end(success ? "<h1>Completing PeekTag sign-in</h1><p>Return to the terminal to confirm the connection.</p>" : "<h1>PeekTag sign-in failed</h1><p>Return to the terminal.</p>");
|
|
122
126
|
clearTimeout(timer);
|
|
123
|
-
if (
|
|
124
|
-
fail(new Error("OAuth state validation failed."));
|
|
125
|
-
else if (error)
|
|
127
|
+
if (error)
|
|
126
128
|
fail(new Error(`OAuth login failed: ${error}`));
|
|
127
129
|
else if (!authorizationCode)
|
|
128
130
|
fail(new Error("OAuth callback did not include an authorization code."));
|
|
129
131
|
else
|
|
130
132
|
settle(authorizationCode);
|
|
131
133
|
});
|
|
132
|
-
resolve({ redirectUri: `http://127.0.0.1:${address.port}/callback`, code, close: () => server.close() });
|
|
134
|
+
resolve({ redirectUri: `http://127.0.0.1:${address.port}/callback`, code, close: () => { clearTimeout(timer); server.close(); } });
|
|
133
135
|
});
|
|
134
136
|
});
|
|
135
137
|
try {
|
|
@@ -143,8 +145,8 @@ export async function login(config, open = openBrowser) {
|
|
|
143
145
|
code_challenge: challenge,
|
|
144
146
|
code_challenge_method: "S256",
|
|
145
147
|
}).toString();
|
|
146
|
-
|
|
147
|
-
const code = await callback.code;
|
|
148
|
+
// Attach the rejection handler before opening the browser: callbacks may arrive immediately.
|
|
149
|
+
const [, code] = await Promise.all([Promise.resolve().then(() => open(authorizationUrl.toString())), callback.code]);
|
|
148
150
|
const tokenResponse = await tokenRequest(metadata.token_endpoint, {
|
|
149
151
|
grant_type: "authorization_code",
|
|
150
152
|
client_id: config.clientId,
|
|
@@ -162,24 +164,26 @@ export async function login(config, open = openBrowser) {
|
|
|
162
164
|
}
|
|
163
165
|
export async function logout(config) {
|
|
164
166
|
const tokens = await readStoredTokens(config);
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
if (
|
|
168
|
-
await
|
|
167
|
+
let removed = false;
|
|
168
|
+
try {
|
|
169
|
+
if (tokens?.refreshToken) {
|
|
170
|
+
const metadata = await discover(config);
|
|
171
|
+
if (!metadata.revocation_endpoint)
|
|
172
|
+
throw new Error("The OAuth provider did not advertise token revocation.");
|
|
173
|
+
const response = await fetch(assertHttpsOrLoopback(metadata.revocation_endpoint, "OAuth revocation endpoint"), {
|
|
169
174
|
method: "POST",
|
|
170
175
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
171
176
|
body: new URLSearchParams({ token: tokens.refreshToken, token_type_hint: "refresh_token", client_id: config.clientId }),
|
|
172
|
-
|
|
177
|
+
signal: AbortSignal.timeout(OAUTH_REQUEST_TIMEOUT_MS),
|
|
178
|
+
});
|
|
179
|
+
if (!response.ok)
|
|
180
|
+
throw new Error(`OAuth token revocation failed (${response.status}). Local credentials were removed; revoke the session in PeekTag account settings.`);
|
|
173
181
|
}
|
|
174
182
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
178
|
-
catch (error) {
|
|
179
|
-
if (/NoEntry/i.test(error.message))
|
|
180
|
-
return false;
|
|
181
|
-
throw error;
|
|
183
|
+
finally {
|
|
184
|
+
removed = await deleteCredential(keyring(config));
|
|
182
185
|
}
|
|
186
|
+
return removed;
|
|
183
187
|
}
|
|
184
188
|
export function tokenIdentity(accessToken) {
|
|
185
189
|
const payload = accessToken.split(".")[1];
|
package/dist/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/browser.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
export function browserCommand(url, platform) {
|
|
3
|
+
if (platform === "win32")
|
|
4
|
+
return { command: "rundll32.exe", args: ["url.dll,FileProtocolHandler", url] };
|
|
5
|
+
return { command: platform === "darwin" ? "open" : "xdg-open", args: [url] };
|
|
6
|
+
}
|
|
7
|
+
export async function openSignInBrowser(url) {
|
|
8
|
+
const { command, args } = browserCommand(url, process.platform);
|
|
9
|
+
await new Promise((resolve, reject) => {
|
|
10
|
+
// Pass the whole authorization URL as an argument, without a shell interpreting its query string.
|
|
11
|
+
const child = spawn(command, args, { detached: true, stdio: "ignore", windowsHide: true, shell: false });
|
|
12
|
+
child.once("error", () => reject(new Error("Could not open the sign-in browser. Check your default browser and try again.")));
|
|
13
|
+
child.once("spawn", () => { child.unref(); resolve(); });
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,MAAM,UAAU,cAAc,CAAC,GAAW,EAAE,QAAyB;IACnE,IAAI,QAAQ,KAAK,OAAO;QAAE,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,6BAA6B,EAAE,GAAG,CAAC,EAAE,CAAC;IACzG,OAAO,EAAE,OAAO,EAAE,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;AAC/E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,GAAW;IACjD,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChE,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,kGAAkG;QAClG,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;QACzG,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,+EAA+E,CAAC,CAAC,CAAC,CAAC;QAC9H,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/cli.js
CHANGED
|
@@ -31,7 +31,7 @@ function addSearchOptions(command) {
|
|
|
31
31
|
const program = new Command()
|
|
32
32
|
.name("peektag")
|
|
33
33
|
.description("Use PeekTag from the command line and MCP-compatible agents.")
|
|
34
|
-
.version("0.1.
|
|
34
|
+
.version("0.1.2")
|
|
35
35
|
.option("--json", "Print machine-readable JSON")
|
|
36
36
|
.option("--timeout <seconds>", "Request timeout in seconds", "60")
|
|
37
37
|
.showSuggestionAfterError();
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface CredentialEntry {
|
|
2
|
+
getPassword(): Promise<string | null | undefined>;
|
|
3
|
+
setPassword(value: string): Promise<void>;
|
|
4
|
+
deleteCredential(): Promise<boolean>;
|
|
5
|
+
}
|
|
6
|
+
type EntryFactory = (suffix: string) => CredentialEntry;
|
|
7
|
+
export declare function readCredential(entry: EntryFactory): Promise<string | undefined>;
|
|
8
|
+
export declare function writeCredential(entry: EntryFactory, value: string): Promise<void>;
|
|
9
|
+
export declare function deleteCredential(entry: EntryFactory): Promise<boolean>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
const CHUNK_LENGTH = 1000;
|
|
3
|
+
const MAX_CHUNKS = 64;
|
|
4
|
+
function manifest(value) {
|
|
5
|
+
const parsed = JSON.parse(value);
|
|
6
|
+
if (parsed.format !== "peektag-keychain-v1")
|
|
7
|
+
return undefined;
|
|
8
|
+
if (!/^[a-f0-9-]{36}$/.test(parsed.generation ?? "") || !Number.isInteger(parsed.count) || parsed.count < 1 || parsed.count > MAX_CHUNKS) {
|
|
9
|
+
throw new Error("The keychain credential manifest is invalid. Sign in again.");
|
|
10
|
+
}
|
|
11
|
+
return parsed;
|
|
12
|
+
}
|
|
13
|
+
async function readEntry(entry) {
|
|
14
|
+
try {
|
|
15
|
+
return await entry.getPassword() ?? undefined;
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
if (/NoEntry/i.test(error.message))
|
|
19
|
+
return undefined;
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
async function removeEntry(entry) {
|
|
24
|
+
try {
|
|
25
|
+
return await entry.deleteCredential();
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
if (/NoEntry/i.test(error.message))
|
|
29
|
+
return false;
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const partSuffix = (value, index) => `|${value.generation}|${index}`;
|
|
34
|
+
export async function readCredential(entry) {
|
|
35
|
+
// A refresh can replace the manifest while another CLI process is reading it.
|
|
36
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
37
|
+
const value = await readEntry(entry(""));
|
|
38
|
+
if (!value)
|
|
39
|
+
return undefined;
|
|
40
|
+
const stored = manifest(value);
|
|
41
|
+
if (!stored)
|
|
42
|
+
return value;
|
|
43
|
+
const parts = await Promise.all(Array.from({ length: stored.count }, (_, index) => readEntry(entry(partSuffix(stored, index)))));
|
|
44
|
+
if (parts.every(part => part !== undefined))
|
|
45
|
+
return parts.join("");
|
|
46
|
+
if (value === await readEntry(entry("")))
|
|
47
|
+
throw new Error("Stored credentials are incomplete. Sign in again.");
|
|
48
|
+
}
|
|
49
|
+
throw new Error("The keychain changed during the read. Retry the command.");
|
|
50
|
+
}
|
|
51
|
+
export async function writeCredential(entry, value) {
|
|
52
|
+
const previous = await readEntry(entry(""));
|
|
53
|
+
let oldManifest;
|
|
54
|
+
// New authorization must be able to replace a damaged legacy entry.
|
|
55
|
+
if (previous) {
|
|
56
|
+
try {
|
|
57
|
+
oldManifest = manifest(previous);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
oldManifest = undefined;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Each chunk stays below Windows' UTF-16 credential size limit, including surrogate pairs.
|
|
64
|
+
const chunks = [];
|
|
65
|
+
for (const character of value) {
|
|
66
|
+
if (!chunks.length || chunks[chunks.length - 1].length + character.length > CHUNK_LENGTH)
|
|
67
|
+
chunks.push("");
|
|
68
|
+
chunks[chunks.length - 1] += character;
|
|
69
|
+
}
|
|
70
|
+
if (!chunks.length || chunks.length > MAX_CHUNKS)
|
|
71
|
+
throw new Error("Credential size is outside the supported range.");
|
|
72
|
+
const next = { format: "peektag-keychain-v1", generation: randomUUID(), count: chunks.length };
|
|
73
|
+
const created = [];
|
|
74
|
+
try {
|
|
75
|
+
for (const [index, chunk] of chunks.entries()) {
|
|
76
|
+
await entry(partSuffix(next, index)).setPassword(chunk);
|
|
77
|
+
created.push(index);
|
|
78
|
+
}
|
|
79
|
+
// Publish only after every chunk exists; a failed write preserves the previous session.
|
|
80
|
+
await entry("").setPassword(JSON.stringify(next));
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
await Promise.all(created.map(index => removeEntry(entry(partSuffix(next, index)))));
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
if (oldManifest)
|
|
87
|
+
await Promise.all(Array.from({ length: oldManifest.count }, (_, index) => removeEntry(entry(partSuffix(oldManifest, index)))));
|
|
88
|
+
}
|
|
89
|
+
export async function deleteCredential(entry) {
|
|
90
|
+
const value = await readEntry(entry(""));
|
|
91
|
+
if (!value)
|
|
92
|
+
return false;
|
|
93
|
+
const stored = manifest(value);
|
|
94
|
+
if (stored)
|
|
95
|
+
await Promise.all(Array.from({ length: stored.count }, (_, index) => removeEntry(entry(partSuffix(stored, index)))));
|
|
96
|
+
return removeEntry(entry(""));
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=credential-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credential-store.js","sourceRoot":"","sources":["../src/credential-store.ts"],"names":[],"mappings":"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"}
|
package/dist/installer.d.ts
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
1
|
import type { CliConfig } from "./config.js";
|
|
2
2
|
export type McpTarget = "claude-code" | "cursor" | "codex";
|
|
3
|
+
export declare function cursorServerConfig(url: string): {
|
|
4
|
+
url: string;
|
|
5
|
+
auth?: {
|
|
6
|
+
CLIENT_ID: string;
|
|
7
|
+
scopes: string[];
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
export declare function codexInstallArguments(url: string): string[];
|
|
11
|
+
export declare function mergeCursorDocument(document: unknown, url: string): Record<string, unknown>;
|
|
3
12
|
export declare function installMcp(target: McpTarget, config: CliConfig): Promise<string>;
|
package/dist/installer.js
CHANGED
|
@@ -2,7 +2,7 @@ import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
import { spawnSync } from "node:child_process";
|
|
5
|
-
import { assertHttpsOrLoopback } from "./config.js";
|
|
5
|
+
import { assertHttpsOrLoopback, DEFAULT_MCP_URL } from "./config.js";
|
|
6
6
|
function run(command, args) {
|
|
7
7
|
const result = spawnSync(command, args, { stdio: "inherit", shell: process.platform === "win32" });
|
|
8
8
|
if (result.error)
|
|
@@ -10,6 +10,37 @@ function run(command, args) {
|
|
|
10
10
|
if (result.status !== 0)
|
|
11
11
|
throw new Error(`${command} exited with status ${result.status ?? "unknown"}.`);
|
|
12
12
|
}
|
|
13
|
+
export function cursorServerConfig(url) {
|
|
14
|
+
return url === DEFAULT_MCP_URL
|
|
15
|
+
? { url, auth: { CLIENT_ID: "peektag-cursor", scopes: ["peektag.mcp", "offline_access"] } }
|
|
16
|
+
: { url };
|
|
17
|
+
}
|
|
18
|
+
export function codexInstallArguments(url) {
|
|
19
|
+
return ["mcp", "add", "peektag", "--url", url,
|
|
20
|
+
...(url === DEFAULT_MCP_URL ? ["--oauth-client-id", "peektag-codex"] : [])];
|
|
21
|
+
}
|
|
22
|
+
export function mergeCursorDocument(document, url) {
|
|
23
|
+
if (!document || typeof document !== "object" || Array.isArray(document)) {
|
|
24
|
+
throw new Error("Cursor MCP config must be a JSON object.");
|
|
25
|
+
}
|
|
26
|
+
const config = document;
|
|
27
|
+
const servers = config.mcpServers;
|
|
28
|
+
if (servers !== undefined && (!servers || typeof servers !== "object" || Array.isArray(servers))) {
|
|
29
|
+
throw new Error("Cursor mcpServers must be a JSON object.");
|
|
30
|
+
}
|
|
31
|
+
const entries = (servers ?? {});
|
|
32
|
+
const existing = entries.peektag;
|
|
33
|
+
if (existing && (typeof existing !== "object" || Array.isArray(existing) || existing.url !== url)) {
|
|
34
|
+
throw new Error("Cursor already has a different peektag server. Review it before replacing the connection.");
|
|
35
|
+
}
|
|
36
|
+
const existingAuth = existing?.auth;
|
|
37
|
+
if (url === DEFAULT_MCP_URL && existingAuth !== undefined &&
|
|
38
|
+
(!existingAuth || typeof existingAuth !== "object" || Array.isArray(existingAuth) ||
|
|
39
|
+
existingAuth.CLIENT_ID !== "peektag-cursor")) {
|
|
40
|
+
throw new Error("Cursor already has custom PeekTag OAuth settings. Review them before replacing the connection.");
|
|
41
|
+
}
|
|
42
|
+
return { ...config, mcpServers: { ...entries, peektag: { ...(existing ?? {}), ...cursorServerConfig(url) } } };
|
|
43
|
+
}
|
|
13
44
|
async function mergeCursorConfig(url) {
|
|
14
45
|
const path = join(homedir(), ".cursor", "mcp.json");
|
|
15
46
|
let document = {};
|
|
@@ -20,14 +51,14 @@ async function mergeCursorConfig(url) {
|
|
|
20
51
|
if (error.code !== "ENOENT")
|
|
21
52
|
throw new Error(`Cursor MCP config is not valid JSON: ${path}`);
|
|
22
53
|
}
|
|
23
|
-
|
|
54
|
+
const updated = mergeCursorDocument(document, url);
|
|
24
55
|
await mkdir(dirname(path), { recursive: true });
|
|
25
|
-
await writeFile(path, `${JSON.stringify(
|
|
56
|
+
await writeFile(path, `${JSON.stringify(updated, null, 2)}\n`, "utf8");
|
|
26
57
|
return path;
|
|
27
58
|
}
|
|
28
59
|
export async function installMcp(target, config) {
|
|
29
60
|
const mcpUrl = assertHttpsOrLoopback(config.mcpUrl, "MCP URL").toString();
|
|
30
|
-
if (process.platform === "win32" && /[&|<>"
|
|
61
|
+
if (process.platform === "win32" && /[&|<>"^%!]/.test(mcpUrl)) {
|
|
31
62
|
throw new Error("The MCP URL contains characters that cannot be passed safely to a Windows agent installer.");
|
|
32
63
|
}
|
|
33
64
|
if (target === "cursor")
|
|
@@ -36,7 +67,7 @@ export async function installMcp(target, config) {
|
|
|
36
67
|
run("claude", ["mcp", "add", "--transport", "http", "--scope", "user", "peektag", mcpUrl]);
|
|
37
68
|
return "PeekTag added to Claude Code. Run /mcp in Claude Code to sign in.";
|
|
38
69
|
}
|
|
39
|
-
run("codex",
|
|
40
|
-
return "PeekTag added to Codex.
|
|
70
|
+
run("codex", codexInstallArguments(mcpUrl));
|
|
71
|
+
return "PeekTag added to Codex. If authentication is needed, run `codex mcp login peektag --scopes peektag.mcp,offline_access`.";
|
|
41
72
|
}
|
|
42
73
|
//# sourceMappingURL=installer.js.map
|
package/dist/installer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"installer.js","sourceRoot":"","sources":["../src/installer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"installer.js","sourceRoot":"","sources":["../src/installer.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp.js
CHANGED
|
@@ -2,7 +2,7 @@ import { Client, StreamableHTTPClientTransport } from "@modelcontextprotocol/cli
|
|
|
2
2
|
import { assertHttpsOrLoopback } from "./config.js";
|
|
3
3
|
import { getAccessToken } from "./auth.js";
|
|
4
4
|
export class PeekTagMcpClient {
|
|
5
|
-
#client = new Client({ name: "peektag-cli", version: "0.1.
|
|
5
|
+
#client = new Client({ name: "peektag-cli", version: "0.1.2" });
|
|
6
6
|
#config;
|
|
7
7
|
#timeoutMs;
|
|
8
8
|
#transport;
|