@naturali/cli 0.27.3 → 0.28.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.
Files changed (3) hide show
  1. package/README.md +6 -10
  2. package/dist/index.mjs +32 -60
  3. package/package.json +2 -3
package/README.md CHANGED
@@ -5,23 +5,19 @@ operation, generated from the [OpenAPI specs](../../api/openapi/).
5
5
 
6
6
  ```bash
7
7
  pnpm add -g @naturali/cli
8
- naturali configure
8
+ export NATURALI_TOKEN=nat_sk_...
9
9
  ```
10
10
 
11
11
  ## Configuration
12
12
 
13
- `naturali configure` saves a profile to `~/.naturali/config.json`: a token
14
- (`nat_sk_…` or a session JWT). The CLI always talks to `https://api.naturali.ai`
15
- the only naturali.ai API origin, and not configurable.
16
-
17
- Environment variables take precedence, which is what CI should use:
13
+ The CLI always talks to `https://api.naturali.ai` the only naturali.ai API
14
+ origin, and not configurable. Credentials and the default project come from
15
+ the environment:
18
16
 
19
17
  | Variable | Purpose |
20
18
  | --- | --- |
21
- | `NATURALI_TOKEN` | Bearer credential. When set, no profile is needed. |
22
- | `NATURALI_PROFILE` | Profile to use when `--profile` is not passed. Defaults to `default`. |
23
-
24
- Use `--profile <name>` to switch profiles per command.
19
+ | `NATURALI_TOKEN` | Bearer credential (`nat_sk_…` or a session JWT). Required. |
20
+ | `NATURALI_PROJECT` | Default `--project-id` for commands that take one. An explicit `--project-id` still wins. |
25
21
 
26
22
  ## Commands
27
23
 
package/dist/index.mjs CHANGED
@@ -1,9 +1,6 @@
1
- import * as path from "node:path";
1
+ import * as nodePath from "node:path";
2
2
  import { fileURLToPath } from "node:url";
3
- import password from "@inquirer/password";
4
3
  import { Command } from "commander";
5
- import * as fs from "node:fs";
6
- import * as os from "node:os";
7
4
  //#region \0rolldown/runtime.js
8
5
  var __defProp = Object.defineProperty;
9
6
  var __exportAll = (all, no_symbols) => {
@@ -17,7 +14,7 @@ var __exportAll = (all, no_symbols) => {
17
14
  };
18
15
  //#endregion
19
16
  //#region package.json
20
- var version = "0.27.3";
17
+ var version = "0.28.0";
21
18
  //#endregion
22
19
  //#region ../sdk/src/generated/core/bodySerializer.gen.ts
23
20
  const jsonBodySerializer = { bodySerializer: (body) => JSON.stringify(body, (_key, value) => typeof value === "bigint" ? value.toString() : value) };
@@ -1822,24 +1819,6 @@ var src_exports = /* @__PURE__ */ __exportAll({
1822
1819
  //#region src/config.ts
1823
1820
  /** The naturali.ai API origin. Not configurable — there is only one. */
1824
1821
  const API_BASE_URL = "https://api.naturali.ai";
1825
- const CONFIG_FILE = path.join(os.homedir(), ".naturali", "config.json");
1826
- const readConfig = () => {
1827
- try {
1828
- return JSON.parse(fs.readFileSync(CONFIG_FILE, "utf8"));
1829
- } catch {
1830
- return {};
1831
- }
1832
- };
1833
- const writeProfile = (name, profile) => {
1834
- const config = readConfig();
1835
- config[name] = profile;
1836
- fs.mkdirSync(path.dirname(CONFIG_FILE), { recursive: true });
1837
- fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
1838
- };
1839
- /** Where the config file lives, so `configure` can name it in its output. */
1840
- const configFilePath = () => {
1841
- return CONFIG_FILE;
1842
- };
1843
1822
  const buildClient = (args) => {
1844
1823
  const { token } = args;
1845
1824
  return createClient(createConfig({
@@ -1848,20 +1827,14 @@ const buildClient = (args) => {
1848
1827
  }));
1849
1828
  };
1850
1829
  /**
1851
- * Resolves credentials in precedence order:
1830
+ * Resolves credentials from `NATURALI_TOKEN`.
1852
1831
  *
1853
- * 1. `NATURALI_TOKEN` no profile needed.
1854
- * 2. A named profile (`--profile` → `NATURALI_PROFILE` → `default`).
1855
- *
1856
- * Exits with an actionable message when neither applies.
1832
+ * Exits with an actionable message when it is unset.
1857
1833
  */
1858
- const resolveContext = (profileName) => {
1859
- const envToken = process.env["NATURALI_TOKEN"];
1860
- if (envToken) return { client: buildClient({ token: envToken }) };
1861
- const name = profileName ?? process.env["NATURALI_PROFILE"] ?? "default";
1862
- const profile = readConfig()[name];
1863
- if (profile) return { client: buildClient({ token: profile.token }) };
1864
- console.error(`Profile "${name}" not found. Run: naturali configure${name !== "default" ? ` --profile ${name}` : ""}\nOr set NATURALI_TOKEN in the environment.`);
1834
+ const resolveContext = () => {
1835
+ const token = process.env["NATURALI_TOKEN"];
1836
+ if (token) return { client: buildClient({ token }) };
1837
+ console.error("NATURALI_TOKEN is not set. Set it to a nat_sk_… API key or a session JWT.");
1865
1838
  process.exit(1);
1866
1839
  };
1867
1840
  //#endregion
@@ -1954,10 +1927,6 @@ const buildArrayFlagValue = (rawValues) => {
1954
1927
  const oneLine = (text) => {
1955
1928
  return text.replace(/\s+/g, " ").trim();
1956
1929
  };
1957
- const GLOBAL_FLAGS = [{
1958
- name: "profile",
1959
- description: "config profile to use"
1960
- }];
1961
1930
  /**
1962
1931
  * Renders `naturali <command> --help`: the operation's own description, a link
1963
1932
  * to the module docs page, and every flag the spec declares — grouped so it is
@@ -2000,21 +1969,16 @@ const renderCommandHelp = (args) => {
2000
1969
  }
2001
1970
  lines.push("");
2002
1971
  }
2003
- lines.push("Global flags:");
2004
- for (const flag of GLOBAL_FLAGS) lines.push(` --${flag.name} <string> ${flag.description}`);
2005
1972
  return lines.join("\n");
2006
1973
  };
2007
1974
  //#endregion
2008
1975
  //#region src/routeCall.ts
2009
- /** Flags the dispatcher owns, never forwarded to the API. */
2010
- const RESERVED_FLAGS = /* @__PURE__ */ new Set(["profile"]);
2011
1976
  const placeFlags = (args) => {
2012
1977
  const { route, parsedFlags, call } = args;
2013
1978
  const typeByCanonical = new Map(route.flags.map((flag) => {
2014
1979
  return [toCanonical(flag.name), flag.type];
2015
1980
  }));
2016
1981
  for (const [flagKey, rawValue] of Object.entries(parsedFlags.single)) {
2017
- if (RESERVED_FLAGS.has(flagKey)) continue;
2018
1982
  const canonical = toCanonical(flagKey);
2019
1983
  const value = typeByCanonical.get(canonical) === "array" ? buildArrayFlagValue(parsedFlags.repeated[flagKey] ?? [rawValue]) : parseFlagValue(rawValue);
2020
1984
  const pathParam = route.pathParams.find((param) => {
@@ -2038,6 +2002,19 @@ const placeFlags = (args) => {
2038
2002
  call.body[kebabToSnake(flagKey)] = value;
2039
2003
  }
2040
2004
  };
2005
+ const PROJECT_ID_PARAM = "project_id";
2006
+ /**
2007
+ * Falls back to `NATURALI_PROJECT` for the `project_id` path or query
2008
+ * parameter when a command doesn't pass `--project-id` explicitly, so a user
2009
+ * working within one project doesn't have to repeat it on every command.
2010
+ */
2011
+ const applyProjectIdEnvDefault = (args) => {
2012
+ const { route, call } = args;
2013
+ const envProjectId = process.env["NATURALI_PROJECT"];
2014
+ if (!envProjectId) return;
2015
+ if (route.pathParams.includes(PROJECT_ID_PARAM) && !(PROJECT_ID_PARAM in call.path)) call.path[PROJECT_ID_PARAM] = envProjectId;
2016
+ else if (route.queryParams.includes(PROJECT_ID_PARAM) && !(PROJECT_ID_PARAM in call.query)) call.query[PROJECT_ID_PARAM] = envProjectId;
2017
+ };
2041
2018
  /**
2042
2019
  * Turns parsed flags into the `{ path, query, body }` an SDK method expects.
2043
2020
  *
@@ -2056,6 +2033,10 @@ const buildRouteCall = (args) => {
2056
2033
  parsedFlags,
2057
2034
  call
2058
2035
  });
2036
+ applyProjectIdEnvDefault({
2037
+ route,
2038
+ call
2039
+ });
2059
2040
  const missingPathParams = route.pathParams.filter((param) => {
2060
2041
  return !(param in call.path);
2061
2042
  });
@@ -2133,7 +2114,7 @@ const formatError = (args) => {
2133
2114
  * parameter, a missing SDK method, or a non-2xx response.
2134
2115
  */
2135
2116
  const dispatchCommand = async (args) => {
2136
- const { commandName, route, rawArgs, profileFromProgram } = args;
2117
+ const { commandName, route, rawArgs } = args;
2137
2118
  if (rawArgs.includes("--help") || rawArgs.includes("-h")) {
2138
2119
  console.log(renderCommandHelp({
2139
2120
  commandName,
@@ -2142,7 +2123,7 @@ const dispatchCommand = async (args) => {
2142
2123
  process.exit(0);
2143
2124
  }
2144
2125
  const parsedFlags = parseUnknownWithRepeats({ cliArgs: rawArgs });
2145
- const context = resolveContext(parsedFlags.single["profile"] ?? profileFromProgram);
2126
+ const context = resolveContext();
2146
2127
  const built = buildRouteCall({
2147
2128
  route,
2148
2129
  parsedFlags
@@ -5166,16 +5147,9 @@ const routes = {
5166
5147
  * Every API operation is a command, generated from `api/openapi/v1/*.yaml` into
5167
5148
  * `src/generated/routes.ts` and dispatched through `@naturali/sdk` — so the CLI
5168
5149
  * is a thin client over exactly the public contract (api/API.md), with nothing
5169
- * hand-written per endpoint. Only credential management (`configure`) and
5170
- * discovery (`list-commands`) are commands of its own.
5150
+ * hand-written per endpoint. Only discovery (`list-commands`) is a command of
5151
+ * its own. Credentials come from the `NATURALI_TOKEN` environment variable.
5171
5152
  */
5172
- const addConfigureCommand = (program) => {
5173
- program.command("configure").description(`Save credentials to a named profile (${configFilePath()})`).option("-p, --profile <name>", "profile name", "default").action(async (opts) => {
5174
- const token = await password({ message: "Token (nat_sk_… or a session JWT, hidden):" });
5175
- writeProfile(opts.profile, { token });
5176
- console.log(`Profile "${opts.profile}" saved to ${configFilePath()}.`);
5177
- });
5178
- };
5179
5153
  const addListCommandsCommand = (program) => {
5180
5154
  program.command("list-commands").description("List every available API command").action(() => {
5181
5155
  const entries = Object.entries(routes).sort(([a], [b]) => {
@@ -5208,8 +5182,7 @@ const addDynamicDispatch = (program) => {
5208
5182
  await dispatchCommand({
5209
5183
  commandName,
5210
5184
  route,
5211
- rawArgs: commandIdx >= 0 ? process.argv.slice(commandIdx + 1) : [],
5212
- profileFromProgram: program.opts().profile
5185
+ rawArgs: commandIdx >= 0 ? process.argv.slice(commandIdx + 1) : []
5213
5186
  });
5214
5187
  });
5215
5188
  };
@@ -5223,9 +5196,8 @@ const addDynamicDispatch = (program) => {
5223
5196
  */
5224
5197
  const createProgram = () => {
5225
5198
  const program = new Command();
5226
- program.name("naturali").description("naturali.ai CLI").version(version).option("-p, --profile <name>", "config profile to use");
5199
+ program.name("naturali").description("naturali.ai CLI").version(version);
5227
5200
  program.addHelpText("after", "\nRun `naturali list-commands` to see every API command, and\n`naturali <command> --help` for a command's flags and docs link.");
5228
- addConfigureCommand(program);
5229
5201
  addListCommandsCommand(program);
5230
5202
  addDynamicDispatch(program);
5231
5203
  return program;
@@ -5241,7 +5213,7 @@ const runCli = async (args) => {
5241
5213
  };
5242
5214
  if ((() => {
5243
5215
  if (!process.argv[1]) return false;
5244
- return path.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
5216
+ return nodePath.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
5245
5217
  })()) runCli(process.argv);
5246
5218
  //#endregion
5247
5219
  export { createProgram, runCli };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturali/cli",
3
- "version": "0.27.3",
3
+ "version": "0.28.0",
4
4
  "description": "Command-line interface for the naturali.ai API, generated from its OpenAPI specs",
5
5
  "type": "module",
6
6
  "bin": {
@@ -21,7 +21,6 @@
21
21
  "access": "public"
22
22
  },
23
23
  "dependencies": {
24
- "@inquirer/password": "^5.1.1",
25
24
  "commander": "^15.0.0"
26
25
  },
27
26
  "devDependencies": {
@@ -31,7 +30,7 @@
31
30
  "tsx": "^4.23.1",
32
31
  "typescript": "~6.0.3",
33
32
  "vitest": "^4.1.10",
34
- "@naturali/sdk": "0.27.3"
33
+ "@naturali/sdk": "0.28.0"
35
34
  },
36
35
  "scripts": {
37
36
  "generate": "tsx scripts/generate.ts",