@m6d/cortex-cli 0.21.0 → 0.23.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@m6d/cortex-cli",
3
- "version": "0.21.0",
3
+ "version": "0.23.0",
4
4
  "description": "Scaffold Cortex projects and manage a Cortex deployment",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -98,7 +98,7 @@ async function login(given: string | undefined, name: string) {
98
98
  const typed =
99
99
  given ??
100
100
  (prompts.canAsk()
101
- ? await prompts.askValue("Cortex URL", "https://cortex.example.com")
101
+ ? await prompts.askValue("Cortex URL", { hint: "https://cortex.example.com" })
102
102
  : report.fail({
103
103
  what: "No terminal to ask for the Cortex URL",
104
104
  blocks: ["Pass it with --url."],
@@ -544,13 +544,16 @@ async function collectInput(
544
544
  return Object.fromEntries(body);
545
545
  }
546
546
 
547
- /** Asks for one field until the answer parses the way the flag would. */
547
+ /** Asks for one field until the answer parses the way the flag would; blank is `null` where allowed. */
548
548
  async function askUntilValid(flag: Flag) {
549
- const hint = flag.choices?.join(" | ") ?? flag.description ?? flag.kind;
549
+ const hint = flag.choices?.join(" | ") ?? (flag.description || flag.kind);
550
550
  for (;;) {
551
551
  const answer = flag.sensitive
552
- ? await prompts.askSecret(flag.name)
553
- : await prompts.askValue(flag.name, hint);
552
+ ? await prompts.askSecret(flag.name, { blank: flag.nullable })
553
+ : await prompts.askValue(flag.name, {
554
+ hint: flag.nullable ? `${hint} (blank for none)` : hint,
555
+ blank: flag.nullable,
556
+ });
554
557
  const value = parseAnswer(flag, answer);
555
558
  if (value !== undefined) return value;
556
559
  report.note(`${flag.name} must be ${flag.choices ? `one of ${hint}` : `a ${flag.kind}`}.`);
@@ -499,20 +499,27 @@ async function askAndSave() {
499
499
  export async function askProvider() {
500
500
  for (;;) {
501
501
  const name = (
502
- await prompts.askValue("Model provider name", "openai", issue("MODEL_PROVIDER_NAME"))
502
+ await prompts.askValue("Model provider name", {
503
+ hint: "openai",
504
+ check: issue("MODEL_PROVIDER_NAME"),
505
+ })
503
506
  ).trim();
504
507
  const baseUrl = (
505
- await prompts.askValue(
506
- "Base URL",
507
- "Any OpenAI-compatible URL, e.g. https://api.openai.com/v1",
508
- issue("MODEL_PROVIDER_URL"),
509
- )
508
+ await prompts.askValue("Base URL", {
509
+ hint: "Any OpenAI-compatible URL, e.g. https://api.openai.com/v1",
510
+ check: issue("MODEL_PROVIDER_URL"),
511
+ })
510
512
  )
511
513
  .trim()
512
514
  .replace(/\/+$/, "");
513
- const apiKey = await prompts.askSecret("API key", issue("MODEL_PROVIDER_API_KEY"));
515
+ const apiKey = await prompts.askSecret("API key", {
516
+ check: issue("MODEL_PROVIDER_API_KEY"),
517
+ });
514
518
  const model = (
515
- await prompts.askValue("Model", "gpt-5-mini", issue("MODEL_PROVIDER_MODEL"))
519
+ await prompts.askValue("Model", {
520
+ hint: "gpt-5-mini",
521
+ check: issue("MODEL_PROVIDER_MODEL"),
522
+ })
516
523
  ).trim();
517
524
  const provider = { name, baseUrl, apiKey, model };
518
525
 
@@ -60,6 +60,27 @@ export type LocationResult = LatLng & { accuracy?: number };
60
60
 
61
61
  export type RequestLocationOutcome = ClientToolOutcome<LocationResult>;
62
62
 
63
+ /**
64
+ * Asks the end user to connect their own account to an MCP server that signs
65
+ * in each end user. Its call is stamped with where the sign-in starts
66
+ * (`ConnectAccountBinding` in the wire contract).
67
+ */
68
+ export const CONNECT_ACCOUNT_TOOL = "connectAccount";
69
+
70
+ /** The model's arguments: the MCP server to connect, by name. */
71
+ export type ConnectAccountInput = { server: string };
72
+
73
+ /**
74
+ * `completed` once the account is connected with the access it needs,
75
+ * `cancelled` when the end user said Not now or cancelled the sign-in,
76
+ * `failed` when the sign-in came back without that access, or ran out
77
+ * first.
78
+ */
79
+ export type ConnectAccountOutcome = ClientToolOutcome<never>;
80
+
81
+ /** How long a sign-in Cortex starts stays open, and so how long the widget waits for its connection. */
82
+ export const SIGN_IN_TTL_MS = 10 * 60 * 1000;
83
+
63
84
  /**
64
85
  * Parse a `message` event into a handshake, or null when the origin doesn't
65
86
  * match the tool's `embedOrigin` or the payload isn't a well-formed handshake.
@@ -10,6 +10,7 @@ export {
10
10
  canCarrySecret,
11
11
  egressAllowedHosts,
12
12
  isEgressAllowedHost,
13
+ isLoopback,
13
14
  isPrivateAddress,
14
15
  normalizeHost,
15
16
  } from "./url";
@@ -79,7 +79,7 @@ export function isPrivateAddress(address: string) {
79
79
  }
80
80
 
81
81
  /** Loopback by its normalized spelling: `[::1]` arrives from a URL without its brackets. */
82
- function isLoopback(hostname: string) {
82
+ export function isLoopback(hostname: string) {
83
83
  return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1";
84
84
  }
85
85