primcli 1.69.0 → 1.70.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/oclif/index.js +166 -24
- package/package.json +1 -1
package/dist/oclif/index.js
CHANGED
|
@@ -44956,7 +44956,7 @@ const PRIMITIVE_TEAM_AUTHOR = {
|
|
|
44956
44956
|
url: "https://primitive.dev"
|
|
44957
44957
|
};
|
|
44958
44958
|
const SDK_VERSION_RANGE = "^2.0.0";
|
|
44959
|
-
const CLI_VERSION_RANGE = "^1.
|
|
44959
|
+
const CLI_VERSION_RANGE = "^1.70.0";
|
|
44960
44960
|
const ESBUILD_VERSION_RANGE = "^0.27.0";
|
|
44961
44961
|
function renderHandler() {
|
|
44962
44962
|
return `// env.PRIMITIVE_API_KEY, env.PRIMITIVE_WEBHOOK_SECRET, and
|
|
@@ -50376,14 +50376,7 @@ var ListenPendingCommand = class ListenPendingCommand extends Command {
|
|
|
50376
50376
|
}
|
|
50377
50377
|
};
|
|
50378
50378
|
//#endregion
|
|
50379
|
-
//#region src/oclif/
|
|
50380
|
-
const MAX_CLI_LOGIN_POLL_INTERVAL_SECONDS = 60;
|
|
50381
|
-
function cliError$3(message) {
|
|
50382
|
-
return new Errors.CLIError(message, { exit: 1 });
|
|
50383
|
-
}
|
|
50384
|
-
function sleep(ms) {
|
|
50385
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
50386
|
-
}
|
|
50379
|
+
//#region src/oclif/browser-login-prompt.ts
|
|
50387
50380
|
function openBrowser(url) {
|
|
50388
50381
|
const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
|
|
50389
50382
|
const args = process.platform === "win32" ? [
|
|
@@ -50399,6 +50392,143 @@ function openBrowser(url) {
|
|
|
50399
50392
|
child.on("error", () => void 0);
|
|
50400
50393
|
child.unref();
|
|
50401
50394
|
}
|
|
50395
|
+
/**
|
|
50396
|
+
* The copy-URL hotkey needs raw keypresses from a terminal and a terminal
|
|
50397
|
+
* to show the hint on. Anything else (CI, agents, piped output) gets the
|
|
50398
|
+
* plain URL and never blocks on input.
|
|
50399
|
+
*/
|
|
50400
|
+
function canOfferCopyHotkey(input, output) {
|
|
50401
|
+
return Boolean(input.isTTY && output.isTTY && typeof input.setRawMode === "function");
|
|
50402
|
+
}
|
|
50403
|
+
function formatBrowserLoginInstructions(params) {
|
|
50404
|
+
const { copyHotkey, openedBrowser, start } = params;
|
|
50405
|
+
const copyHint = copyHotkey ? " (c to copy)" : "";
|
|
50406
|
+
const lines = [`Your sign-in code is: ${start.user_code}`];
|
|
50407
|
+
if (openedBrowser) lines.push("Opening Primitive in your browser...", "", `Browser didn't open, or want a different one? Use this URL${copyHint}:`);
|
|
50408
|
+
else lines.push("", `Open this URL in any browser to sign in${copyHint}:`);
|
|
50409
|
+
lines.push(` ${start.verification_uri_complete}`);
|
|
50410
|
+
if (start.verification_uri !== start.verification_uri_complete) lines.push(`On another device, go to ${start.verification_uri} and enter ${start.user_code}.`);
|
|
50411
|
+
lines.push("");
|
|
50412
|
+
return `${lines.join("\n")}\n`;
|
|
50413
|
+
}
|
|
50414
|
+
/**
|
|
50415
|
+
* OSC 52 asks the terminal emulator itself to set the clipboard, so it
|
|
50416
|
+
* works over SSH, where a local clipboard command would copy on the
|
|
50417
|
+
* remote host instead of the machine the user is sitting at.
|
|
50418
|
+
*/
|
|
50419
|
+
function osc52Sequence(text) {
|
|
50420
|
+
return `\u001b]52;c;${Buffer.from(text, "utf8").toString("base64")}\u0007`;
|
|
50421
|
+
}
|
|
50422
|
+
function nativeClipboardCommand() {
|
|
50423
|
+
if (process.env.SSH_CONNECTION || process.env.SSH_TTY) return null;
|
|
50424
|
+
if (process.platform === "darwin") return ["pbcopy", []];
|
|
50425
|
+
if (process.platform === "win32") return ["clip", []];
|
|
50426
|
+
if (process.env.WAYLAND_DISPLAY) return ["wl-copy", []];
|
|
50427
|
+
if (process.env.DISPLAY) return ["xclip", ["-selection", "clipboard"]];
|
|
50428
|
+
return null;
|
|
50429
|
+
}
|
|
50430
|
+
/**
|
|
50431
|
+
* Resolves false on any failure, including a tool that exits before
|
|
50432
|
+
* reading its input (EPIPE on stdin), so the caller falls back to OSC 52
|
|
50433
|
+
* instead of the error taking down login.
|
|
50434
|
+
*/
|
|
50435
|
+
function runClipboardCommand(command, args, text) {
|
|
50436
|
+
return new Promise((resolve) => {
|
|
50437
|
+
let inputFailed = false;
|
|
50438
|
+
const child = spawn(command, args, { stdio: [
|
|
50439
|
+
"pipe",
|
|
50440
|
+
"ignore",
|
|
50441
|
+
"ignore"
|
|
50442
|
+
] });
|
|
50443
|
+
child.on("error", () => resolve(false));
|
|
50444
|
+
child.stdin.on("error", () => {
|
|
50445
|
+
inputFailed = true;
|
|
50446
|
+
});
|
|
50447
|
+
child.on("close", (code) => resolve(code === 0 && !inputFailed));
|
|
50448
|
+
child.stdin.end(text);
|
|
50449
|
+
});
|
|
50450
|
+
}
|
|
50451
|
+
function copyWithNativeClipboard(text) {
|
|
50452
|
+
const command = nativeClipboardCommand();
|
|
50453
|
+
if (!command) return Promise.resolve(false);
|
|
50454
|
+
return runClipboardCommand(command[0], command[1], text);
|
|
50455
|
+
}
|
|
50456
|
+
/**
|
|
50457
|
+
* Copies via the native clipboard when running locally and always emits
|
|
50458
|
+
* OSC 52 as well. Terminals without OSC 52 support (macOS Terminal.app)
|
|
50459
|
+
* are covered by the native path; SSH sessions are covered by OSC 52.
|
|
50460
|
+
*/
|
|
50461
|
+
async function copyToClipboard(text, output, native = copyWithNativeClipboard) {
|
|
50462
|
+
output.write(osc52Sequence(text));
|
|
50463
|
+
return await native(text) ? "native" : "terminal";
|
|
50464
|
+
}
|
|
50465
|
+
const CTRL_C = "";
|
|
50466
|
+
const CTRL_Z = "";
|
|
50467
|
+
/**
|
|
50468
|
+
* Listens for `c` while the CLI polls for browser approval. Raw mode turns
|
|
50469
|
+
* Ctrl+C and Ctrl+Z into plain input, so they are handled here: Ctrl+C is
|
|
50470
|
+
* re-raised as SIGINT, and Ctrl+Z restores the terminal, suspends with
|
|
50471
|
+
* SIGTSTP, and re-enters raw mode on SIGCONT. Several keys can arrive in
|
|
50472
|
+
* one chunk (pastes, SSH), so every character is checked. Returns a
|
|
50473
|
+
* disposer that restores the terminal.
|
|
50474
|
+
*/
|
|
50475
|
+
function listenForCopyHotkey(params) {
|
|
50476
|
+
const { input, output, url } = params;
|
|
50477
|
+
const copy = params.copy ?? copyToClipboard;
|
|
50478
|
+
let disposed = false;
|
|
50479
|
+
const copyUrl = () => {
|
|
50480
|
+
copy(url, output).then((how) => {
|
|
50481
|
+
if (disposed) return;
|
|
50482
|
+
output.write(how === "native" ? "Copied the sign-in URL to your clipboard.\n" : "Sent the sign-in URL to your terminal's clipboard. If nothing was copied, select the URL above instead.\n");
|
|
50483
|
+
});
|
|
50484
|
+
};
|
|
50485
|
+
const onContinue = () => {
|
|
50486
|
+
if (!disposed) input.setRawMode?.(true);
|
|
50487
|
+
};
|
|
50488
|
+
const suspend = () => {
|
|
50489
|
+
input.setRawMode?.(false);
|
|
50490
|
+
process.once("SIGCONT", onContinue);
|
|
50491
|
+
process.kill(process.pid, "SIGTSTP");
|
|
50492
|
+
};
|
|
50493
|
+
const onData = (chunk) => {
|
|
50494
|
+
let wantsCopy = false;
|
|
50495
|
+
for (const key of chunk.toString()) {
|
|
50496
|
+
if (key === CTRL_C) {
|
|
50497
|
+
dispose();
|
|
50498
|
+
process.kill(process.pid, "SIGINT");
|
|
50499
|
+
return;
|
|
50500
|
+
}
|
|
50501
|
+
if (key === CTRL_Z && process.platform !== "win32") {
|
|
50502
|
+
if (wantsCopy) copyUrl();
|
|
50503
|
+
suspend();
|
|
50504
|
+
return;
|
|
50505
|
+
}
|
|
50506
|
+
if (key === "c" || key === "C") wantsCopy = true;
|
|
50507
|
+
}
|
|
50508
|
+
if (wantsCopy) copyUrl();
|
|
50509
|
+
};
|
|
50510
|
+
const dispose = () => {
|
|
50511
|
+
if (disposed) return;
|
|
50512
|
+
disposed = true;
|
|
50513
|
+
input.off("data", onData);
|
|
50514
|
+
process.off("SIGCONT", onContinue);
|
|
50515
|
+
input.setRawMode?.(false);
|
|
50516
|
+
input.pause();
|
|
50517
|
+
};
|
|
50518
|
+
input.setRawMode?.(true);
|
|
50519
|
+
input.on("data", onData);
|
|
50520
|
+
input.resume();
|
|
50521
|
+
return dispose;
|
|
50522
|
+
}
|
|
50523
|
+
//#endregion
|
|
50524
|
+
//#region src/oclif/commands/login.ts
|
|
50525
|
+
const MAX_CLI_LOGIN_POLL_INTERVAL_SECONDS = 60;
|
|
50526
|
+
function cliError$3(message) {
|
|
50527
|
+
return new Errors.CLIError(message, { exit: 1 });
|
|
50528
|
+
}
|
|
50529
|
+
function sleep(ms) {
|
|
50530
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
50531
|
+
}
|
|
50402
50532
|
function unwrapData$2(value) {
|
|
50403
50533
|
return value?.data ?? null;
|
|
50404
50534
|
}
|
|
@@ -50584,22 +50714,34 @@ var LoginCommand$1 = class extends Command {
|
|
|
50584
50714
|
}
|
|
50585
50715
|
const start = unwrapData$2(started.data);
|
|
50586
50716
|
if (!start) throw cliError$3("Primitive API returned an empty CLI login response.");
|
|
50587
|
-
|
|
50588
|
-
if (
|
|
50589
|
-
|
|
50590
|
-
|
|
50591
|
-
|
|
50592
|
-
|
|
50593
|
-
|
|
50594
|
-
|
|
50595
|
-
|
|
50596
|
-
|
|
50597
|
-
|
|
50598
|
-
responseStyle: "fields"
|
|
50599
|
-
}),
|
|
50600
|
-
retryCommand,
|
|
50717
|
+
const openedBrowser = !flags["no-browser"];
|
|
50718
|
+
if (openedBrowser) openBrowser(start.verification_uri_complete);
|
|
50719
|
+
const copyHotkey = canOfferCopyHotkey(process.stdin, process.stderr);
|
|
50720
|
+
const stopCopyHotkey = copyHotkey ? listenForCopyHotkey({
|
|
50721
|
+
input: process.stdin,
|
|
50722
|
+
output: process.stderr,
|
|
50723
|
+
url: start.verification_uri_complete
|
|
50724
|
+
}) : () => void 0;
|
|
50725
|
+
process.stderr.write(formatBrowserLoginInstructions({
|
|
50726
|
+
copyHotkey,
|
|
50727
|
+
openedBrowser,
|
|
50601
50728
|
start
|
|
50602
|
-
});
|
|
50729
|
+
}));
|
|
50730
|
+
process.stderr.write("Waiting for browser approval...\n");
|
|
50731
|
+
let login;
|
|
50732
|
+
try {
|
|
50733
|
+
login = await pollCliLoginUntilApproved({
|
|
50734
|
+
poll: (deviceCode) => pollCliLogin({
|
|
50735
|
+
body: { device_code: deviceCode },
|
|
50736
|
+
client: apiClient.client,
|
|
50737
|
+
responseStyle: "fields"
|
|
50738
|
+
}),
|
|
50739
|
+
retryCommand,
|
|
50740
|
+
start
|
|
50741
|
+
});
|
|
50742
|
+
} finally {
|
|
50743
|
+
stopCopyHotkey();
|
|
50744
|
+
}
|
|
50603
50745
|
deleteChatState(this.config.configDir);
|
|
50604
50746
|
saveCliCredentials(this.config.configDir, {
|
|
50605
50747
|
access_token: login.access_token,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "primcli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.70.0",
|
|
4
4
|
"description": "Official Primitive CLI: deploy Primitive Functions, send and inspect mail, manage endpoints, all from the terminal. Wraps the @primitivedotdev/sdk runtime client with one-shot commands.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|