@paybond/kit 0.9.7 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/audit-export.d.ts +7 -0
- package/dist/cli/audit-export.js +120 -0
- package/dist/cli/automation.d.ts +25 -0
- package/dist/cli/automation.js +297 -0
- package/dist/cli/body.d.ts +7 -0
- package/dist/cli/body.js +22 -0
- package/dist/cli/color.d.ts +15 -0
- package/dist/cli/color.js +39 -0
- package/dist/cli/command-spec.d.ts +12 -0
- package/dist/cli/command-spec.js +330 -0
- package/dist/cli/commands/discovery.d.ts +8 -0
- package/dist/cli/commands/discovery.js +194 -0
- package/dist/cli/commands/setup.d.ts +15 -0
- package/dist/cli/commands/setup.js +397 -0
- package/dist/cli/commands/workflows.d.ts +7 -0
- package/dist/cli/commands/workflows.js +209 -0
- package/dist/cli/config.d.ts +14 -0
- package/dist/cli/config.js +96 -0
- package/dist/cli/context.d.ts +22 -0
- package/dist/cli/context.js +109 -0
- package/dist/cli/credentials.d.ts +21 -0
- package/dist/cli/credentials.js +141 -0
- package/dist/cli/doctor-agent.d.ts +15 -0
- package/dist/cli/doctor-agent.js +311 -0
- package/dist/cli/envelope.d.ts +14 -0
- package/dist/cli/envelope.js +46 -0
- package/dist/cli/globals.d.ts +22 -0
- package/dist/cli/globals.js +238 -0
- package/dist/cli/help.d.ts +3 -0
- package/dist/cli/help.js +51 -0
- package/dist/cli/mcp-install.d.ts +41 -0
- package/dist/cli/mcp-install.js +95 -0
- package/dist/cli/mcp-policy.d.ts +23 -0
- package/dist/cli/mcp-policy.js +104 -0
- package/dist/cli/mcp-verify-config.d.ts +37 -0
- package/dist/cli/mcp-verify-config.js +174 -0
- package/dist/cli/redact.d.ts +4 -0
- package/dist/cli/redact.js +67 -0
- package/dist/cli/request-id.d.ts +2 -0
- package/dist/cli/request-id.js +5 -0
- package/dist/cli/router.d.ts +2 -0
- package/dist/cli/router.js +275 -0
- package/dist/cli/suggest.d.ts +4 -0
- package/dist/cli/suggest.js +58 -0
- package/dist/cli/support-diagnostics.d.ts +19 -0
- package/dist/cli/support-diagnostics.js +47 -0
- package/dist/cli/types.d.ts +72 -0
- package/dist/cli/types.js +60 -0
- package/dist/cli/ux.d.ts +8 -0
- package/dist/cli/ux.js +164 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +38 -0
- package/dist/index.d.ts +46 -12
- package/dist/index.js +136 -47
- package/dist/init.js +9 -14
- package/dist/login.d.ts +14 -1
- package/dist/login.js +123 -63
- package/dist/mcp-server.d.ts +4 -0
- package/dist/mcp-server.js +204 -76
- package/package.json +5 -2
package/dist/login.d.ts
CHANGED
|
@@ -10,6 +10,17 @@ export type LoginOptions = {
|
|
|
10
10
|
noOpen: boolean;
|
|
11
11
|
force: boolean;
|
|
12
12
|
};
|
|
13
|
+
export type LoginResult = {
|
|
14
|
+
envPath: string;
|
|
15
|
+
keyMasked: string;
|
|
16
|
+
keyWritten: true;
|
|
17
|
+
environment: DeviceEnvironment;
|
|
18
|
+
tenantId: string;
|
|
19
|
+
tenantUuid: string;
|
|
20
|
+
expiresAt?: string;
|
|
21
|
+
verificationUri: string;
|
|
22
|
+
userCode: string;
|
|
23
|
+
};
|
|
13
24
|
type FetchInput = string | URL;
|
|
14
25
|
type FetchInit = {
|
|
15
26
|
method?: string;
|
|
@@ -25,11 +36,13 @@ export type LoginDependencies = {
|
|
|
25
36
|
stdout?: Writable;
|
|
26
37
|
stderr?: Writable;
|
|
27
38
|
now?: () => number;
|
|
39
|
+
/** When false, suppress human-readable progress lines (for JSON CLI output). */
|
|
40
|
+
humanOutput?: boolean;
|
|
28
41
|
};
|
|
29
42
|
export declare function parseArgs(argv: string[]): LoginOptions | "help";
|
|
30
43
|
export declare function assertGitIgnored(envPath: string, cwd: string): Promise<void>;
|
|
31
44
|
export declare function assertCanWriteEnvFile(envPath: string, force: boolean): Promise<void>;
|
|
32
45
|
export declare function writeEnvFile(envPath: string, rawKey: string, force: boolean): Promise<void>;
|
|
33
|
-
export declare function runLogin(options: LoginOptions, deps?: LoginDependencies): Promise<
|
|
46
|
+
export declare function runLogin(options: LoginOptions, deps?: LoginDependencies): Promise<LoginResult>;
|
|
34
47
|
export declare function main(argv?: string[], deps?: LoginDependencies): Promise<number>;
|
|
35
48
|
export {};
|
package/dist/login.js
CHANGED
|
@@ -1,10 +1,30 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
|
+
import { runCli } from "./cli/router.js";
|
|
2
7
|
const DEFAULT_GATEWAY = "https://api.paybond.ai";
|
|
3
8
|
const DEFAULT_ENV_FILE = ".env.local";
|
|
4
9
|
const CLIENT_ID = "paybond-kit-cli";
|
|
5
10
|
const CLIENT_NAME = "Paybond CLI";
|
|
6
11
|
const DEVICE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
7
12
|
const MIN_POLL_INTERVAL_SECONDS = 1;
|
|
13
|
+
const DEFAULT_DEVICE_EXPIRES_IN_SECONDS = 600;
|
|
14
|
+
const DEFAULT_DEVICE_POLL_INTERVAL_SECONDS = 5;
|
|
15
|
+
const MS_PER_SECOND = 1_000;
|
|
16
|
+
const DEVICE_EXPIRY_GRACE_MS = MS_PER_SECOND;
|
|
17
|
+
const PROCESS_EXIT_SUCCESS = 0;
|
|
18
|
+
const SPAWN_COMMAND_NOT_FOUND_EXIT_CODE = 127;
|
|
19
|
+
const GIT_CHECK_IGNORE_MATCHED = PROCESS_EXIT_SUCCESS;
|
|
20
|
+
const GIT_CHECK_IGNORE_NOT_MATCHED = 1;
|
|
21
|
+
const MAX_GIT_WORKTREE_WALK_DEPTH = 256;
|
|
22
|
+
const ENV_FILE_MODE = 0o600;
|
|
23
|
+
const GITIGNORE_FILE_MODE = 0o644;
|
|
24
|
+
const API_KEY_MASK_MIN_PARTS = 5;
|
|
25
|
+
const API_KEY_MASK_MIN_ID_LENGTH = 12;
|
|
26
|
+
const API_KEY_MASK_ID_PREFIX_LENGTH = 8;
|
|
27
|
+
const API_KEY_MASK_ID_SUFFIX_LENGTH = 4;
|
|
8
28
|
class PaybondLoginError extends Error {
|
|
9
29
|
constructor(message) {
|
|
10
30
|
super(message);
|
|
@@ -127,19 +147,9 @@ function replaceOrAppendEnvValue(existing, rawKey, force) {
|
|
|
127
147
|
const suffix = existing.length > 0 && !existing.endsWith("\n") ? "\n" : "";
|
|
128
148
|
return `${existing}${suffix}${line}\n`;
|
|
129
149
|
}
|
|
130
|
-
async function pathModule() {
|
|
131
|
-
// @ts-expect-error Node builtins are available in the published CLI runtime.
|
|
132
|
-
return await import("node:path");
|
|
133
|
-
}
|
|
134
|
-
async function fsModule() {
|
|
135
|
-
// @ts-expect-error Node builtins are available in the published CLI runtime.
|
|
136
|
-
return await import("node:fs/promises");
|
|
137
|
-
}
|
|
138
150
|
async function spawnCommand(command, args, cwd) {
|
|
139
|
-
// @ts-expect-error Node builtins are available in the published CLI runtime.
|
|
140
|
-
const childProcess = await import("node:child_process");
|
|
141
151
|
return await new Promise((resolve) => {
|
|
142
|
-
const child =
|
|
152
|
+
const child = spawn(command, args, {
|
|
143
153
|
cwd,
|
|
144
154
|
stdio: ["ignore", "pipe", "pipe"],
|
|
145
155
|
});
|
|
@@ -152,7 +162,7 @@ async function spawnCommand(command, args, cwd) {
|
|
|
152
162
|
stderr += String(chunk);
|
|
153
163
|
});
|
|
154
164
|
child.on("error", (err) => {
|
|
155
|
-
resolve({ code:
|
|
165
|
+
resolve({ code: SPAWN_COMMAND_NOT_FOUND_EXIT_CODE, stdout: "", stderr: err.message });
|
|
156
166
|
});
|
|
157
167
|
child.on("close", (code) => {
|
|
158
168
|
resolve({ code, stdout, stderr });
|
|
@@ -160,31 +170,55 @@ async function spawnCommand(command, args, cwd) {
|
|
|
160
170
|
});
|
|
161
171
|
}
|
|
162
172
|
async function resolveEnvFile(envFile, cwd) {
|
|
163
|
-
const path = await pathModule();
|
|
164
173
|
return path.isAbsolute(envFile) ? path.resolve(envFile) : path.resolve(cwd, envFile);
|
|
165
174
|
}
|
|
166
175
|
export async function assertGitIgnored(envPath, cwd) {
|
|
167
176
|
await ensureGitIgnored(envPath, cwd, false);
|
|
168
177
|
}
|
|
178
|
+
async function inGitWorkTree(start) {
|
|
179
|
+
let current = path.resolve(start);
|
|
180
|
+
for (let depth = 0; depth < MAX_GIT_WORKTREE_WALK_DEPTH; depth += 1) {
|
|
181
|
+
try {
|
|
182
|
+
await fs.access(path.join(current, ".git"));
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
// continue walking parents
|
|
187
|
+
}
|
|
188
|
+
const parent = path.dirname(current);
|
|
189
|
+
if (parent === current) {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
current = parent;
|
|
193
|
+
}
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
function gitMissingForSecretWriteError() {
|
|
197
|
+
return new PaybondLoginError("git is required to verify the env file is ignored before writing secrets; install git or pass --env-file outside the repository");
|
|
198
|
+
}
|
|
169
199
|
async function ensureGitIgnored(envPath, cwd, autoAddDefaultEnvFile) {
|
|
170
|
-
const path = await pathModule();
|
|
171
|
-
const fs = await fsModule();
|
|
172
200
|
const rootResult = await spawnCommand("git", ["rev-parse", "--show-toplevel"], cwd);
|
|
173
201
|
if (rootResult.code !== 0) {
|
|
202
|
+
if (rootResult.code === SPAWN_COMMAND_NOT_FOUND_EXIT_CODE || /ENOENT/i.test(rootResult.stderr)) {
|
|
203
|
+
if (await inGitWorkTree(cwd)) {
|
|
204
|
+
throw gitMissingForSecretWriteError();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
174
207
|
return;
|
|
175
208
|
}
|
|
176
209
|
const repoRoot = await fs.realpath(path.resolve(rootResult.stdout.trim()));
|
|
177
210
|
const targetDir = await fs.realpath(path.dirname(path.resolve(envPath)));
|
|
178
211
|
const target = path.resolve(targetDir, path.basename(envPath));
|
|
179
212
|
const relativeTarget = path.relative(repoRoot, target);
|
|
180
|
-
if (relativeTarget !== "" &&
|
|
213
|
+
if (relativeTarget !== "" &&
|
|
214
|
+
(relativeTarget.startsWith("..") || path.isAbsolute(relativeTarget))) {
|
|
181
215
|
return;
|
|
182
216
|
}
|
|
183
217
|
const ignoreResult = await spawnCommand("git", ["-C", repoRoot, "check-ignore", "--quiet", "--", relativeTarget], cwd);
|
|
184
|
-
if (ignoreResult.code ===
|
|
218
|
+
if (ignoreResult.code === GIT_CHECK_IGNORE_MATCHED) {
|
|
185
219
|
return;
|
|
186
220
|
}
|
|
187
|
-
if (ignoreResult.code ===
|
|
221
|
+
if (ignoreResult.code === GIT_CHECK_IGNORE_NOT_MATCHED) {
|
|
188
222
|
if (autoAddDefaultEnvFile && relativeTarget === DEFAULT_ENV_FILE) {
|
|
189
223
|
const gitignorePath = path.resolve(repoRoot, ".gitignore");
|
|
190
224
|
let existing = "";
|
|
@@ -192,14 +226,17 @@ async function ensureGitIgnored(envPath, cwd, autoAddDefaultEnvFile) {
|
|
|
192
226
|
existing = await fs.readFile(gitignorePath, "utf8");
|
|
193
227
|
}
|
|
194
228
|
catch (err) {
|
|
195
|
-
if (!(err &&
|
|
229
|
+
if (!(err &&
|
|
230
|
+
typeof err === "object" &&
|
|
231
|
+
"code" in err &&
|
|
232
|
+
err.code === "ENOENT")) {
|
|
196
233
|
throw err;
|
|
197
234
|
}
|
|
198
235
|
}
|
|
199
236
|
const suffix = existing.length > 0 && !existing.endsWith("\n") ? "\n" : "";
|
|
200
|
-
await fs.writeFile(gitignorePath, `${existing}${suffix}${DEFAULT_ENV_FILE}\n`, { encoding: "utf8", mode:
|
|
237
|
+
await fs.writeFile(gitignorePath, `${existing}${suffix}${DEFAULT_ENV_FILE}\n`, { encoding: "utf8", mode: GITIGNORE_FILE_MODE });
|
|
201
238
|
const recheck = await spawnCommand("git", ["-C", repoRoot, "check-ignore", "--quiet", "--", relativeTarget], cwd);
|
|
202
|
-
if (recheck.code ===
|
|
239
|
+
if (recheck.code === GIT_CHECK_IGNORE_MATCHED) {
|
|
203
240
|
return;
|
|
204
241
|
}
|
|
205
242
|
}
|
|
@@ -208,7 +245,6 @@ async function ensureGitIgnored(envPath, cwd, autoAddDefaultEnvFile) {
|
|
|
208
245
|
throw new PaybondLoginError(`Unable to verify git ignore status for ${target}: ${ignoreResult.stderr.trim() || "git check-ignore failed"}`);
|
|
209
246
|
}
|
|
210
247
|
export async function assertCanWriteEnvFile(envPath, force) {
|
|
211
|
-
const fs = await fsModule();
|
|
212
248
|
try {
|
|
213
249
|
const existing = await fs.readFile(envPath, "utf8");
|
|
214
250
|
if (envKeyPattern().test(existing) && !force) {
|
|
@@ -216,26 +252,31 @@ export async function assertCanWriteEnvFile(envPath, force) {
|
|
|
216
252
|
}
|
|
217
253
|
}
|
|
218
254
|
catch (err) {
|
|
219
|
-
if (err &&
|
|
255
|
+
if (err &&
|
|
256
|
+
typeof err === "object" &&
|
|
257
|
+
"code" in err &&
|
|
258
|
+
err.code === "ENOENT") {
|
|
220
259
|
return;
|
|
221
260
|
}
|
|
222
261
|
throw err;
|
|
223
262
|
}
|
|
224
263
|
}
|
|
225
264
|
export async function writeEnvFile(envPath, rawKey, force) {
|
|
226
|
-
const fs = await fsModule();
|
|
227
265
|
let existing = "";
|
|
228
266
|
try {
|
|
229
267
|
existing = await fs.readFile(envPath, "utf8");
|
|
230
268
|
}
|
|
231
269
|
catch (err) {
|
|
232
|
-
if (!(err &&
|
|
270
|
+
if (!(err &&
|
|
271
|
+
typeof err === "object" &&
|
|
272
|
+
"code" in err &&
|
|
273
|
+
err.code === "ENOENT")) {
|
|
233
274
|
throw err;
|
|
234
275
|
}
|
|
235
276
|
}
|
|
236
277
|
const next = replaceOrAppendEnvValue(existing, rawKey, force);
|
|
237
|
-
await fs.writeFile(envPath, next, { encoding: "utf8", mode:
|
|
238
|
-
await fs.chmod(envPath,
|
|
278
|
+
await fs.writeFile(envPath, next, { encoding: "utf8", mode: ENV_FILE_MODE });
|
|
279
|
+
await fs.chmod(envPath, ENV_FILE_MODE);
|
|
239
280
|
}
|
|
240
281
|
function gatewayUrl(base, path) {
|
|
241
282
|
return `${base.trim().replace(/\/+$/, "")}${path}`;
|
|
@@ -278,7 +319,8 @@ async function postGatewayJson(fetchFn, gateway, path, body) {
|
|
|
278
319
|
if (error) {
|
|
279
320
|
throw new OAuthPollError({
|
|
280
321
|
error,
|
|
281
|
-
error_description: stringField(parsed, "error_description") ||
|
|
322
|
+
error_description: stringField(parsed, "error_description") ||
|
|
323
|
+
stringField(parsed, "message"),
|
|
282
324
|
interval: numberField(parsed, "interval", 0) || undefined,
|
|
283
325
|
});
|
|
284
326
|
}
|
|
@@ -290,10 +332,12 @@ function toDeviceStartResponse(body) {
|
|
|
290
332
|
user_code: stringField(body, "user_code"),
|
|
291
333
|
verification_uri: stringField(body, "verification_uri"),
|
|
292
334
|
verification_uri_complete: stringField(body, "verification_uri_complete") || undefined,
|
|
293
|
-
expires_in: numberField(body, "expires_in",
|
|
294
|
-
interval: numberField(body, "interval",
|
|
335
|
+
expires_in: numberField(body, "expires_in", DEFAULT_DEVICE_EXPIRES_IN_SECONDS),
|
|
336
|
+
interval: numberField(body, "interval", DEFAULT_DEVICE_POLL_INTERVAL_SECONDS),
|
|
295
337
|
};
|
|
296
|
-
if (!response.device_code ||
|
|
338
|
+
if (!response.device_code ||
|
|
339
|
+
!response.user_code ||
|
|
340
|
+
!response.verification_uri) {
|
|
297
341
|
throw new PaybondLoginError("Gateway device start response was missing required fields.");
|
|
298
342
|
}
|
|
299
343
|
return response;
|
|
@@ -332,11 +376,11 @@ async function startDeviceFlow(fetchFn, gateway, environment) {
|
|
|
332
376
|
return toDeviceStartResponse(body);
|
|
333
377
|
}
|
|
334
378
|
async function pollDeviceToken(fetchFn, gateway, environment, start, deps) {
|
|
335
|
-
let intervalSeconds = Math.max(MIN_POLL_INTERVAL_SECONDS, Math.trunc(start.interval ||
|
|
336
|
-
const expiresAtMs = deps.now() + Math.max(1, start.expires_in) *
|
|
379
|
+
let intervalSeconds = Math.max(MIN_POLL_INTERVAL_SECONDS, Math.trunc(start.interval || DEFAULT_DEVICE_POLL_INTERVAL_SECONDS));
|
|
380
|
+
const expiresAtMs = deps.now() + Math.max(1, start.expires_in) * MS_PER_SECOND;
|
|
337
381
|
for (;;) {
|
|
338
|
-
await deps.sleep(intervalSeconds *
|
|
339
|
-
if (deps.now() > expiresAtMs +
|
|
382
|
+
await deps.sleep(intervalSeconds * MS_PER_SECOND);
|
|
383
|
+
if (deps.now() > expiresAtMs + DEVICE_EXPIRY_GRACE_MS) {
|
|
340
384
|
throw new PaybondLoginError("Device authorization expired before approval.");
|
|
341
385
|
}
|
|
342
386
|
try {
|
|
@@ -372,10 +416,12 @@ async function pollDeviceToken(fetchFn, gateway, environment, start, deps) {
|
|
|
372
416
|
function maskAPIKey(rawKey) {
|
|
373
417
|
const trimmed = rawKey.trim();
|
|
374
418
|
const parts = trimmed.split("_");
|
|
375
|
-
if (parts.length >=
|
|
419
|
+
if (parts.length >= API_KEY_MASK_MIN_PARTS && parts[0] === "paybond" && parts[1] === "sk") {
|
|
376
420
|
const environment = parts[2];
|
|
377
421
|
const keyID = parts[3];
|
|
378
|
-
const redactedKeyID = keyID.length >
|
|
422
|
+
const redactedKeyID = keyID.length > API_KEY_MASK_MIN_ID_LENGTH
|
|
423
|
+
? `${keyID.slice(0, API_KEY_MASK_ID_PREFIX_LENGTH)}...${keyID.slice(-API_KEY_MASK_ID_SUFFIX_LENGTH)}`
|
|
424
|
+
: "redacted";
|
|
379
425
|
return `paybond_sk_${environment}_${redactedKeyID}`;
|
|
380
426
|
}
|
|
381
427
|
return "paybond_sk_...";
|
|
@@ -388,11 +434,12 @@ async function defaultOpenBrowser(url) {
|
|
|
388
434
|
const command = platform === "darwin" ? "open" : platform === "win32" ? "cmd" : "xdg-open";
|
|
389
435
|
const args = platform === "win32" ? ["/c", "start", "", url] : [url];
|
|
390
436
|
const result = await spawnCommand(command, args, process.cwd());
|
|
391
|
-
return result.code ===
|
|
437
|
+
return result.code === PROCESS_EXIT_SUCCESS;
|
|
392
438
|
}
|
|
393
439
|
export async function runLogin(options, deps = {}) {
|
|
394
440
|
const cwd = deps.cwd ?? process.cwd();
|
|
395
441
|
const stdout = deps.stdout ?? process.stdout;
|
|
442
|
+
const humanOutput = deps.humanOutput ?? true;
|
|
396
443
|
const fetchFn = deps.fetch ?? fetch;
|
|
397
444
|
const sleep = deps.sleep ?? defaultSleep;
|
|
398
445
|
const now = deps.now ?? Date.now;
|
|
@@ -402,25 +449,40 @@ export async function runLogin(options, deps = {}) {
|
|
|
402
449
|
await ensureGitIgnored(envPath, cwd, options.envFile === DEFAULT_ENV_FILE);
|
|
403
450
|
const start = await startDeviceFlow(fetchFn, options.gateway, options.environment);
|
|
404
451
|
const verificationUrl = start.verification_uri_complete || start.verification_uri;
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
452
|
+
if (humanOutput) {
|
|
453
|
+
stdout.write(`Paybond ${options.environment} login\n`);
|
|
454
|
+
stdout.write(`Verification URL: ${verificationUrl}\n`);
|
|
455
|
+
stdout.write(`Code: ${start.user_code}\n`);
|
|
456
|
+
if (!options.noOpen) {
|
|
457
|
+
const opened = await openBrowser(verificationUrl);
|
|
458
|
+
if (!opened) {
|
|
459
|
+
stdout.write(`Open the verification URL in a browser to approve this login.\n`);
|
|
460
|
+
}
|
|
412
461
|
}
|
|
462
|
+
stdout.write(`Waiting for approval...\n`);
|
|
413
463
|
}
|
|
414
|
-
stdout.write(`Waiting for approval...\n`);
|
|
415
464
|
const token = await pollDeviceToken(fetchFn, options.gateway, options.environment, start, { sleep, now });
|
|
416
465
|
await writeEnvFile(envPath, token.access_token, options.force);
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
stdout.write(`
|
|
466
|
+
const keyMasked = maskAPIKey(token.access_token);
|
|
467
|
+
if (humanOutput) {
|
|
468
|
+
stdout.write(`Wrote PAYBOND_API_KEY to ${envPath}\n`);
|
|
469
|
+
stdout.write(`Key: ${keyMasked}\n`);
|
|
470
|
+
stdout.write(`Target ${token.environment} tenant: ${token.tenant_id} (${token.tenant_uuid})\n`);
|
|
471
|
+
if (token.expires_at) {
|
|
472
|
+
stdout.write(`This key auto-expires at ${token.expires_at}; re-run paybond login to mint a new one.\n`);
|
|
473
|
+
}
|
|
422
474
|
}
|
|
423
|
-
return
|
|
475
|
+
return {
|
|
476
|
+
envPath,
|
|
477
|
+
keyMasked,
|
|
478
|
+
keyWritten: true,
|
|
479
|
+
environment: options.environment,
|
|
480
|
+
tenantId: token.tenant_id,
|
|
481
|
+
tenantUuid: token.tenant_uuid,
|
|
482
|
+
expiresAt: token.expires_at || undefined,
|
|
483
|
+
verificationUri: verificationUrl,
|
|
484
|
+
userCode: start.user_code,
|
|
485
|
+
};
|
|
424
486
|
}
|
|
425
487
|
export async function main(argv = process.argv.slice(2), deps = {}) {
|
|
426
488
|
let parsed;
|
|
@@ -430,7 +492,8 @@ export async function main(argv = process.argv.slice(2), deps = {}) {
|
|
|
430
492
|
(deps.stdout ?? process.stdout).write(`${usage()}\n`);
|
|
431
493
|
return 0;
|
|
432
494
|
}
|
|
433
|
-
|
|
495
|
+
await runLogin(parsed, deps);
|
|
496
|
+
return 0;
|
|
434
497
|
}
|
|
435
498
|
catch (err) {
|
|
436
499
|
(deps.stderr ?? process.stderr).write(`${err instanceof Error ? err.message : String(err)}\n`);
|
|
@@ -438,19 +501,15 @@ export async function main(argv = process.argv.slice(2), deps = {}) {
|
|
|
438
501
|
}
|
|
439
502
|
}
|
|
440
503
|
function normalizeFileURL(url) {
|
|
441
|
-
return url.startsWith("file:///var/")
|
|
504
|
+
return url.startsWith("file:///var/")
|
|
505
|
+
? url.replace("file:///var/", "file:///private/var/")
|
|
506
|
+
: url;
|
|
442
507
|
}
|
|
443
508
|
async function invokedFromCLI() {
|
|
444
509
|
const scriptPath = process.argv[1];
|
|
445
510
|
if (!scriptPath) {
|
|
446
511
|
return false;
|
|
447
512
|
}
|
|
448
|
-
// @ts-ignore Node builtins are available in the published CLI runtime.
|
|
449
|
-
const fs = (await import("node:fs/promises"));
|
|
450
|
-
// @ts-ignore Node builtins are available in the published CLI runtime.
|
|
451
|
-
const path = (await import("node:path"));
|
|
452
|
-
// @ts-ignore Node builtins are available in the published CLI runtime.
|
|
453
|
-
const url = (await import("node:url"));
|
|
454
513
|
async function realFileURL(filePath) {
|
|
455
514
|
let resolved = path.resolve(filePath);
|
|
456
515
|
try {
|
|
@@ -460,15 +519,16 @@ async function invokedFromCLI() {
|
|
|
460
519
|
// If realpath fails, compare the absolute path. This keeps direct execution
|
|
461
520
|
// working even when the script path disappears during process startup.
|
|
462
521
|
}
|
|
463
|
-
return normalizeFileURL(
|
|
522
|
+
return normalizeFileURL(pathToFileURL(resolved).href);
|
|
464
523
|
}
|
|
465
|
-
return (await realFileURL(scriptPath)) ===
|
|
524
|
+
return ((await realFileURL(scriptPath)) ===
|
|
525
|
+
(await realFileURL(fileURLToPath(import.meta.url))));
|
|
466
526
|
}
|
|
467
527
|
invokedFromCLI().then((invoked) => {
|
|
468
528
|
if (!invoked) {
|
|
469
529
|
return;
|
|
470
530
|
}
|
|
471
|
-
|
|
531
|
+
runCli(["login", ...process.argv.slice(2)]).then((code) => {
|
|
472
532
|
process.exitCode = code;
|
|
473
533
|
}, (err) => {
|
|
474
534
|
process.stderr.write(`${err instanceof Error ? err.message : String(err)}\n`);
|
package/dist/mcp-server.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { type McpToolPolicyConfig } from "./cli/mcp-policy.js";
|
|
2
3
|
type JSONRPCID = string | number | null;
|
|
3
4
|
type JSONRPCRequest = {
|
|
4
5
|
jsonrpc?: unknown;
|
|
@@ -28,10 +29,13 @@ export type PaybondMCPSettings = {
|
|
|
28
29
|
gatewayBaseUrl?: string;
|
|
29
30
|
principalPath?: string;
|
|
30
31
|
maxRetries?: number;
|
|
32
|
+
toolPolicy?: McpToolPolicyConfig;
|
|
31
33
|
};
|
|
34
|
+
export declare function formatMcpStdioFrame(response: JSONRPCResponse): string;
|
|
32
35
|
export declare class PaybondMCPServer {
|
|
33
36
|
private readonly runtime;
|
|
34
37
|
private readonly tools;
|
|
38
|
+
private readonly toolPolicy;
|
|
35
39
|
private initialized;
|
|
36
40
|
constructor(settings: PaybondMCPSettings);
|
|
37
41
|
listTools(): Array<Record<string, unknown>>;
|