@primitivedotdev/cli 1.2.0 → 1.2.1
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 +2 -0
- package/dist/oclif/index.js +147 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,6 +16,8 @@ primitive whoami
|
|
|
16
16
|
prim whoami
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
The same CLI is also published unscoped as [`primcli`](https://www.npmjs.com/package/primcli) — `npm install -g primcli` installs an identical build with the same `primitive`/`prim` commands. Use whichever name you prefer; they track the same version.
|
|
20
|
+
|
|
19
21
|
Or with no install:
|
|
20
22
|
|
|
21
23
|
```bash
|
package/dist/oclif/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { A as PrimitiveApiClient, C as saveCliCredentials, D as loadActiveChatSt
|
|
|
2
2
|
import { Args, Command, Errors, Flags, ux } from "@oclif/core";
|
|
3
3
|
import { chmodSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, readdirSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
5
|
-
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
5
|
+
import path, { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
6
6
|
import { hostname } from "node:os";
|
|
7
7
|
import process$1 from "node:process";
|
|
8
8
|
import { createInterface } from "node:readline/promises";
|
|
@@ -20942,6 +20942,74 @@ var SignupCommand = class SignupCommand extends Command {
|
|
|
20942
20942
|
}
|
|
20943
20943
|
}
|
|
20944
20944
|
};
|
|
20945
|
+
function resolveVerificationCode(input) {
|
|
20946
|
+
const sources = [
|
|
20947
|
+
input.positional !== void 0 ? "positional" : null,
|
|
20948
|
+
input.fromStdin === true ? "--code-from-stdin" : null,
|
|
20949
|
+
input.fromFile !== void 0 ? "--code-from-file" : null,
|
|
20950
|
+
input.fromEnv !== void 0 ? "--code-from-env" : null
|
|
20951
|
+
].filter((v) => v !== null);
|
|
20952
|
+
if (sources.length === 0) return {
|
|
20953
|
+
kind: "error",
|
|
20954
|
+
message: "Pass the verification code as a positional argument or via one of --code-from-stdin, --code-from-file, or --code-from-env."
|
|
20955
|
+
};
|
|
20956
|
+
if (sources.length > 1) return {
|
|
20957
|
+
kind: "error",
|
|
20958
|
+
message: `Pass exactly one source for the verification code; got ${sources.join(", ")}.`
|
|
20959
|
+
};
|
|
20960
|
+
if (input.positional !== void 0) return {
|
|
20961
|
+
kind: "ok",
|
|
20962
|
+
code: input.positional
|
|
20963
|
+
};
|
|
20964
|
+
if (input.fromEnv !== void 0) {
|
|
20965
|
+
const value = (input.env ?? process$1.env)[input.fromEnv];
|
|
20966
|
+
if (value === void 0) return {
|
|
20967
|
+
kind: "error",
|
|
20968
|
+
message: `--code-from-env ${input.fromEnv}: environment variable is not set.`
|
|
20969
|
+
};
|
|
20970
|
+
return {
|
|
20971
|
+
kind: "ok",
|
|
20972
|
+
code: stripTrailingNewline(value)
|
|
20973
|
+
};
|
|
20974
|
+
}
|
|
20975
|
+
if (input.fromFile !== void 0) {
|
|
20976
|
+
const readFile = input.readFile ?? defaultReadCodeFile;
|
|
20977
|
+
try {
|
|
20978
|
+
return {
|
|
20979
|
+
kind: "ok",
|
|
20980
|
+
code: stripTrailingNewline(readFile(input.fromFile))
|
|
20981
|
+
};
|
|
20982
|
+
} catch (error) {
|
|
20983
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
20984
|
+
return {
|
|
20985
|
+
kind: "error",
|
|
20986
|
+
message: `--code-from-file ${input.fromFile}: could not read file: ${detail}`
|
|
20987
|
+
};
|
|
20988
|
+
}
|
|
20989
|
+
}
|
|
20990
|
+
const readStdin = input.readStdin ?? defaultReadCodeStdin;
|
|
20991
|
+
try {
|
|
20992
|
+
return {
|
|
20993
|
+
kind: "ok",
|
|
20994
|
+
code: stripTrailingNewline(readStdin())
|
|
20995
|
+
};
|
|
20996
|
+
} catch (error) {
|
|
20997
|
+
return {
|
|
20998
|
+
kind: "error",
|
|
20999
|
+
message: `--code-from-stdin: ${error instanceof Error ? error.message : String(error)}`
|
|
21000
|
+
};
|
|
21001
|
+
}
|
|
21002
|
+
}
|
|
21003
|
+
function stripTrailingNewline(value) {
|
|
21004
|
+
return value.replace(/\r?\n$/, "");
|
|
21005
|
+
}
|
|
21006
|
+
function defaultReadCodeFile(path) {
|
|
21007
|
+
return readFileSync(path, "utf8");
|
|
21008
|
+
}
|
|
21009
|
+
function defaultReadCodeStdin() {
|
|
21010
|
+
if (process$1.stdin.isTTY) throw new Error("stdin is a TTY; pipe the code into this command or use --code-from-file / --code-from-env instead.");
|
|
21011
|
+
return readFileSync(0, "utf8");
|
|
21012
|
+
}
|
|
20945
21013
|
var SignupConfirmCommand = class SignupConfirmCommand extends Command {
|
|
20946
21014
|
static args = {
|
|
20947
21015
|
email: Args.string({
|
|
@@ -20949,19 +21017,28 @@ var SignupConfirmCommand = class SignupConfirmCommand extends Command {
|
|
|
20949
21017
|
required: true
|
|
20950
21018
|
}),
|
|
20951
21019
|
code: Args.string({
|
|
20952
|
-
description: "Verification code from the signup email",
|
|
20953
|
-
required:
|
|
21020
|
+
description: "Verification code from the signup email. Optional when one of --code-from-stdin / --code-from-file / --code-from-env is passed; exactly one source must be set.",
|
|
21021
|
+
required: false
|
|
20954
21022
|
})
|
|
20955
21023
|
};
|
|
20956
21024
|
static description = "Confirm a pending Primitive signup, create an OAuth session, and save CLI credentials locally.";
|
|
20957
21025
|
static summary = "Confirm account signup";
|
|
20958
|
-
static examples = [
|
|
21026
|
+
static examples = [
|
|
21027
|
+
"<%= config.bin %> signup confirm user@example.com 123456",
|
|
21028
|
+
"<%= config.bin %> signup confirm user@example.com 123456 --org-id 00000000-0000-4000-8000-000000000000",
|
|
21029
|
+
"read -rs CODE && CODE=\"$CODE\" <%= config.bin %> signup confirm user@example.com --code-from-env CODE && unset CODE",
|
|
21030
|
+
"read -rs CODE && printf '%s' \"$CODE\" | <%= config.bin %> signup confirm user@example.com --code-from-stdin && unset CODE",
|
|
21031
|
+
"<%= config.bin %> signup confirm user@example.com --code-from-file /run/user/$(id -u)/verification-code"
|
|
21032
|
+
];
|
|
20959
21033
|
static flags = {
|
|
20960
21034
|
"api-base-url": Flags.string({
|
|
20961
21035
|
description: "Override the primary API base URL. Internal testing only; not documented to customers.",
|
|
20962
21036
|
env: "PRIMITIVE_API_BASE_URL",
|
|
20963
21037
|
hidden: true
|
|
20964
21038
|
}),
|
|
21039
|
+
"code-from-stdin": Flags.boolean({ description: "Read the verification code from stdin instead of the positional argument. Use when an agent is constructing the command for the user to run, so the code never enters the agent's prompt context." }),
|
|
21040
|
+
"code-from-file": Flags.string({ description: "Read the verification code from a UTF-8 file at this path. Trailing newlines are stripped." }),
|
|
21041
|
+
"code-from-env": Flags.string({ description: "Read the verification code from this environment variable. Pair with `read -rs CODE && CODE=\"$CODE\" primitive signup confirm <email> --code-from-env CODE && unset CODE` so the value never appears on the command line or in shell history. Plain `read` creates a shell-local variable that child processes cannot see; the inline `CODE=\"$CODE\"` exports it for just the one command." }),
|
|
20965
21042
|
force: Flags.boolean({
|
|
20966
21043
|
char: "f",
|
|
20967
21044
|
description: "Replace saved credentials after verification"
|
|
@@ -20970,6 +21047,13 @@ var SignupConfirmCommand = class SignupConfirmCommand extends Command {
|
|
|
20970
21047
|
};
|
|
20971
21048
|
async run() {
|
|
20972
21049
|
const { args, flags } = await this.parse(SignupConfirmCommand);
|
|
21050
|
+
const resolvedCode = resolveVerificationCode({
|
|
21051
|
+
positional: args.code,
|
|
21052
|
+
fromStdin: flags["code-from-stdin"] === true,
|
|
21053
|
+
fromFile: flags["code-from-file"],
|
|
21054
|
+
fromEnv: flags["code-from-env"]
|
|
21055
|
+
});
|
|
21056
|
+
if (resolvedCode.kind === "error") throw cliError$2(resolvedCode.message);
|
|
20973
21057
|
let releaseCredentialsLock;
|
|
20974
21058
|
try {
|
|
20975
21059
|
releaseCredentialsLock = acquireCliCredentialsLock(this.config.configDir);
|
|
@@ -20978,7 +21062,7 @@ var SignupConfirmCommand = class SignupConfirmCommand extends Command {
|
|
|
20978
21062
|
}
|
|
20979
21063
|
try {
|
|
20980
21064
|
await runSignupConfirmWithCredentialLock({
|
|
20981
|
-
code:
|
|
21065
|
+
code: resolvedCode.code,
|
|
20982
21066
|
configDir: this.config.configDir,
|
|
20983
21067
|
email: args.email,
|
|
20984
21068
|
flags
|
|
@@ -22383,6 +22467,43 @@ function renderFishCompletion(binName) {
|
|
|
22383
22467
|
return `${lines.join("\n")}\n`;
|
|
22384
22468
|
}
|
|
22385
22469
|
//#endregion
|
|
22470
|
+
//#region src/oclif/shell-completion-script.ts
|
|
22471
|
+
/**
|
|
22472
|
+
* Path to the sourceable completion *function* file that
|
|
22473
|
+
* `@oclif/plugin-autocomplete` writes under the CLI cache dir when its cache is
|
|
22474
|
+
* built. This is the artifact a shell is meant to source -- a package manager
|
|
22475
|
+
* dropping a file into `bash_completion.d/` or zsh's `site-functions/` wants
|
|
22476
|
+
* this, NOT the human-readable setup instructions printed by
|
|
22477
|
+
* `<bin> autocomplete <shell>`. The layout mirrors the plugin's own
|
|
22478
|
+
* `Create.bashCompletionFunctionPath` / `zshCompletionFunctionPath` getters:
|
|
22479
|
+
* <cacheDir>/autocomplete/functions/bash/<bin>.bash
|
|
22480
|
+
* <cacheDir>/autocomplete/functions/zsh/_<bin>
|
|
22481
|
+
*
|
|
22482
|
+
* This couples to a private path layout in `@oclif/plugin-autocomplete`
|
|
22483
|
+
* (pinned `^3.2.45` in package.json). If a major bump reorganises that cache
|
|
22484
|
+
* dir, `readCompletionFunction` will fail even after a successful
|
|
22485
|
+
* `--refresh-cache`; re-verify this layout when bumping the plugin.
|
|
22486
|
+
*/
|
|
22487
|
+
function completionFunctionPath(cacheDir, bin, shell) {
|
|
22488
|
+
const functionsDir = path.join(cacheDir, "autocomplete", "functions", shell);
|
|
22489
|
+
const fileName = shell === "bash" ? `${bin}.bash` : `_${bin}`;
|
|
22490
|
+
return path.join(functionsDir, fileName);
|
|
22491
|
+
}
|
|
22492
|
+
/**
|
|
22493
|
+
* Read the generated completion function script, trimmed of trailing
|
|
22494
|
+
* whitespace so the caller can re-add a single newline. Throws an actionable
|
|
22495
|
+
* error (rather than a bare `ENOENT`) if the cached script is missing -- e.g.
|
|
22496
|
+
* the cache build failed, or the plugin changed its path layout.
|
|
22497
|
+
*/
|
|
22498
|
+
function readCompletionFunction(cacheDir, bin, shell) {
|
|
22499
|
+
const filePath = completionFunctionPath(cacheDir, bin, shell);
|
|
22500
|
+
try {
|
|
22501
|
+
return readFileSync(filePath, "utf8").trimEnd();
|
|
22502
|
+
} catch (cause) {
|
|
22503
|
+
throw new Error(`Could not read the generated ${shell} completion script at ${filePath}. Run \`${bin} autocomplete ${shell} --refresh-cache\` and try again.`, { cause });
|
|
22504
|
+
}
|
|
22505
|
+
}
|
|
22506
|
+
//#endregion
|
|
22386
22507
|
//#region src/oclif/index.ts
|
|
22387
22508
|
var ListOperationsCommand = class extends Command {
|
|
22388
22509
|
static description = "List all generated API operations as JSON. Useful for piping to `jq` to discover available commands, their request/response schemas, and per-field descriptions. For inspecting a single operation in detail, prefer `primitive describe <command-or-operation-name>`.";
|
|
@@ -22503,14 +22624,32 @@ var CompletionCommand = class CompletionCommand extends Command {
|
|
|
22503
22624
|
],
|
|
22504
22625
|
required: true
|
|
22505
22626
|
}) };
|
|
22506
|
-
static description =
|
|
22507
|
-
|
|
22627
|
+
static description = `Output a sourceable shell completion script, or print setup instructions.
|
|
22628
|
+
|
|
22629
|
+
For fish, and for bash/zsh when the output is piped or redirected (e.g. into a
|
|
22630
|
+
completion file under bash_completion.d or zsh's site-functions), this emits
|
|
22631
|
+
the raw completion script. For bash/zsh in an interactive terminal it prints
|
|
22632
|
+
the human-readable setup instructions instead. This keeps a redirected
|
|
22633
|
+
\`<%= config.bin %> completion bash > <file>\` safe to source -- the file holds an
|
|
22634
|
+
actual completion function, never instructional prose a shell would choke on.`;
|
|
22635
|
+
static summary = "Output a shell completion script or print setup instructions";
|
|
22636
|
+
static examples = [
|
|
22637
|
+
"<%= config.bin %> completion bash >> /etc/bash_completion.d/primitive",
|
|
22638
|
+
"<%= config.bin %> completion zsh > /usr/local/share/zsh/site-functions/_primitive",
|
|
22639
|
+
"<%= config.bin %> completion fish > ~/.config/fish/completions/primitive.fish"
|
|
22640
|
+
];
|
|
22508
22641
|
async run() {
|
|
22509
22642
|
const { args } = await this.parse(CompletionCommand);
|
|
22510
|
-
|
|
22643
|
+
const shell = args.shell;
|
|
22644
|
+
if (shell === "fish") {
|
|
22511
22645
|
this.log(renderFishCompletion(this.config.bin));
|
|
22512
22646
|
return;
|
|
22513
22647
|
}
|
|
22648
|
+
if ((shell === "bash" || shell === "zsh") && !process.stdout.isTTY) {
|
|
22649
|
+
await this.config.runCommand("autocomplete", [shell, "--refresh-cache"]);
|
|
22650
|
+
this.log(readCompletionFunction(this.config.cacheDir, this.config.bin, shell));
|
|
22651
|
+
return;
|
|
22652
|
+
}
|
|
22514
22653
|
await this.config.runCommand("autocomplete", [args.shell]);
|
|
22515
22654
|
}
|
|
22516
22655
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@primitivedotdev/cli",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.1",
|
|
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,
|