@01.software/cli 0.10.3 → 0.10.5

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/index.js CHANGED
@@ -8,7 +8,7 @@ import { Command } from "commander";
8
8
  import {
9
9
  CollectionClient,
10
10
  ServerCommerceClient
11
- } from "@01.software/sdk";
11
+ } from "@01.software/sdk/server";
12
12
 
13
13
  // src/lib/credentials.ts
14
14
  import {
@@ -166,6 +166,9 @@ function classifyError(err) {
166
166
  if (isPermissionCode(code)) {
167
167
  return { type: "permission", code };
168
168
  }
169
+ if (code === "auth_error" || code === "permission_error") {
170
+ return { type: "permission", code: "credential_invalid" };
171
+ }
169
172
  if (isDegradedCode(code)) {
170
173
  const out = { type: "degraded", code };
171
174
  if (typeof obj.retryAfter === "number") {
@@ -187,7 +190,7 @@ function classifyError(err) {
187
190
  }
188
191
  const name = typeof obj.name === "string" ? obj.name : void 0;
189
192
  const status = typeof obj.status === "number" ? obj.status : void 0;
190
- if (name === "ConfigError" || status === 401) {
193
+ if (name === "ConfigError" || name === "AuthError" || name === "PermissionError" || status === 401 || status === 403) {
191
194
  return { type: "permission", code: "credential_invalid" };
192
195
  }
193
196
  if (name === "NetworkError" || name === "TimeoutError" || status === 408 || status === 503) {
@@ -440,7 +443,14 @@ function exitWithError(error, options = {}) {
440
443
  function isValidBearerToken(secret) {
441
444
  return secret.startsWith("sk01_") || secret.startsWith("pat01_");
442
445
  }
443
- function resolveClient(apiKeyFlag) {
446
+ function credentialError(detail) {
447
+ return {
448
+ type: "permission",
449
+ code: "credential_invalid",
450
+ detail
451
+ };
452
+ }
453
+ function resolveClientCredentials(apiKeyFlag) {
444
454
  let publishableKey = process.env.SOFTWARE_PUBLISHABLE_KEY;
445
455
  let secretKey = apiKeyFlag ?? process.env.SOFTWARE_SECRET_KEY;
446
456
  if (!publishableKey || !secretKey) {
@@ -458,29 +468,25 @@ function resolveClient(apiKeyFlag) {
458
468
  }
459
469
  }
460
470
  if (!publishableKey || !secretKey) {
461
- exitWithError({
462
- type: "permission",
463
- code: "credential_invalid",
464
- detail: {
465
- message: t("AuthenticationRequired"),
466
- steps: [
467
- t("RunLoginToAuthenticate"),
468
- t("PassApiKey"),
469
- t("SetEnvVars")
470
- ]
471
- }
471
+ throw credentialError({
472
+ message: t("AuthenticationRequired"),
473
+ steps: [
474
+ t("RunLoginToAuthenticate"),
475
+ t("PassApiKey"),
476
+ t("SetEnvVars")
477
+ ]
472
478
  });
473
479
  }
474
480
  if (!isValidBearerToken(secretKey)) {
475
- exitWithError({
476
- type: "permission",
477
- code: "credential_invalid",
478
- detail: {
479
- message: t("InvalidApiKeyFormat"),
480
- suggestion: t("RetiredHexCredentialsRejected")
481
- }
481
+ throw credentialError({
482
+ message: t("InvalidApiKeyFormat"),
483
+ suggestion: t("RetiredHexCredentialsRejected")
482
484
  });
483
485
  }
486
+ return { publishableKey, secretKey };
487
+ }
488
+ function resolveClientOrThrow(apiKeyFlag) {
489
+ const { publishableKey, secretKey } = resolveClientCredentials(apiKeyFlag);
484
490
  const serverOptions = { publishableKey, secretKey };
485
491
  return {
486
492
  collections: new CollectionClient(
@@ -495,11 +501,37 @@ function resolveClient(apiKeyFlag) {
495
501
  secretKey
496
502
  };
497
503
  }
504
+ function resolveClient(apiKeyFlag) {
505
+ try {
506
+ return resolveClientOrThrow(apiKeyFlag);
507
+ } catch (error) {
508
+ exitWithError(error);
509
+ }
510
+ }
498
511
 
499
512
  // src/commands/crud.ts
500
513
  import { readFileSync as readFileSync2 } from "fs";
501
514
  import { basename } from "path";
515
+
516
+ // src/lib/collections.ts
502
517
  import { COLLECTIONS } from "@01.software/sdk";
518
+ function validateCollection(name) {
519
+ if (COLLECTIONS.includes(name)) {
520
+ return name;
521
+ }
522
+ const normalized = name.replace(/-/g, "").toLowerCase();
523
+ const suggestions = COLLECTIONS.filter((collection) => {
524
+ const candidate = collection.replace(/-/g, "").toLowerCase();
525
+ return candidate.startsWith(normalized) || normalized.startsWith(candidate) || normalized.length >= 3 && candidate.includes(normalized);
526
+ }).slice(0, 5);
527
+ const hint = suggestions.length > 0 ? `Did you mean: ${suggestions.join(", ")}?` : 'Run "01 --help" for available collections.';
528
+ throw new Error(`Unknown collection "${name}". ${hint}`);
529
+ }
530
+ function parseSelect(input) {
531
+ return Object.fromEntries(
532
+ input.split(",").map((field) => field.trim()).map((field) => [field, true])
533
+ );
534
+ }
503
535
 
504
536
  // src/lib/parse.ts
505
537
  function failArg(label, value, expectedKind) {
@@ -581,21 +613,6 @@ function readFileAsBlob(filePath) {
581
613
  const buffer = readFileSync2(filePath);
582
614
  return { blob: new Blob([buffer]), filename: basename(filePath) };
583
615
  }
584
- function validateCollection(name) {
585
- if (!COLLECTIONS.includes(name)) {
586
- const normalized = name.replace(/-/g, "").toLowerCase();
587
- const suggestions = COLLECTIONS.filter((c) => {
588
- const cn = c.replace(/-/g, "").toLowerCase();
589
- return cn.startsWith(normalized) || normalized.startsWith(cn) || normalized.length >= 3 && cn.includes(normalized);
590
- }).slice(0, 5);
591
- const hint = suggestions.length > 0 ? `Did you mean: ${suggestions.join(", ")}?` : 'Run "01 --help" for available collections.';
592
- throw new Error(`Unknown collection "${name}". ${hint}`);
593
- }
594
- return name;
595
- }
596
- function parseSelect(input) {
597
- return Object.fromEntries(input.split(",").map((f) => [f.trim(), true]));
598
- }
599
616
  function registerCrudCommands(program2, getClient2, getFormat2) {
600
617
  program2.command("query <collection>").description("Query documents from a collection").option("--where <json>", "Filter conditions (JSON)").option("--limit <n>", "Max results", (v) => parseInt(v, 10)).option("--page <n>", "Page number", (v) => parseInt(v, 10)).option("--sort <field>", "Sort field (prefix with - for descending)").option(
601
618
  "--depth <n>",
@@ -1850,6 +1867,207 @@ Prerequisites:
1850
1867
  });
1851
1868
  }
1852
1869
 
1870
+ // src/commands/agent.ts
1871
+ import { COLLECTIONS as COLLECTIONS3 } from "@01.software/sdk";
1872
+
1873
+ // src/lib/agent-output.ts
1874
+ function stringifyAgentJson(data, options = {}) {
1875
+ return options.pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
1876
+ }
1877
+ function asRecord(value) {
1878
+ return value && typeof value === "object" ? value : null;
1879
+ }
1880
+ function errorMessage(error) {
1881
+ const raw = asRecord(error);
1882
+ if (raw) {
1883
+ if (typeof raw.message === "string" && raw.message.length > 0) {
1884
+ return raw.message;
1885
+ }
1886
+ if (raw.detail && typeof raw.detail === "object" && typeof raw.detail.message === "string") {
1887
+ return String(raw.detail.message);
1888
+ }
1889
+ }
1890
+ if (error instanceof Error && error.message.length > 0) {
1891
+ return error.message;
1892
+ }
1893
+ if (typeof error === "string" && error.length > 0) {
1894
+ return error;
1895
+ }
1896
+ return "Internal error";
1897
+ }
1898
+ function isRawNotFound(error) {
1899
+ const raw = asRecord(error);
1900
+ return raw?.status === 404 || raw?.code === "not_found" || raw?.name === "GoneError";
1901
+ }
1902
+ function agentErrorExitCode(code) {
1903
+ switch (code) {
1904
+ case "INVALID_INPUT":
1905
+ return 2;
1906
+ case "AUTH_FAILED":
1907
+ return 3;
1908
+ case "NOT_FOUND":
1909
+ return 4;
1910
+ case "INTERNAL":
1911
+ return 1;
1912
+ }
1913
+ }
1914
+ function classifyAgentError(error) {
1915
+ const adminError = classifyError(error);
1916
+ const message = errorMessage(error);
1917
+ if (isRawNotFound(error) || adminError.code === "not_found") {
1918
+ return { error: { code: "NOT_FOUND", message } };
1919
+ }
1920
+ if (adminError.type === "permission") {
1921
+ return { error: { code: "AUTH_FAILED", message } };
1922
+ }
1923
+ if (adminError.type === "validation" && adminError.code !== "unknown") {
1924
+ return { error: { code: "INVALID_INPUT", message } };
1925
+ }
1926
+ return { error: { code: "INTERNAL", message } };
1927
+ }
1928
+ function printAgentSuccess(data, options = {}) {
1929
+ console.log(stringifyAgentJson(data, options));
1930
+ }
1931
+ function printAgentError(error, options = {}) {
1932
+ const envelope = classifyAgentError(error);
1933
+ console.log(stringifyAgentJson(envelope, options));
1934
+ return envelope;
1935
+ }
1936
+ function exitWithAgentError(error, options = {}) {
1937
+ const envelope = printAgentError(error, options);
1938
+ process.exit(agentErrorExitCode(envelope.error.code));
1939
+ }
1940
+
1941
+ // src/commands/agent.ts
1942
+ var AGENT_PROTOCOL_VERSION = "1";
1943
+ function buildStableAgentFields() {
1944
+ return {
1945
+ id: { type: "string", queryable: true },
1946
+ createdAt: { type: "string", queryable: true },
1947
+ updatedAt: { type: "string", queryable: true }
1948
+ };
1949
+ }
1950
+ function invalidInput(message, field, value) {
1951
+ const error = new Error(message);
1952
+ Object.assign(error, {
1953
+ type: "validation",
1954
+ code: "invalid_argument",
1955
+ field,
1956
+ detail: { message, value, field }
1957
+ });
1958
+ return error;
1959
+ }
1960
+ function parsePositiveInteger(value, field) {
1961
+ if (value == null) return void 0;
1962
+ if (/^[1-9]\d*$/.test(value)) return Number(value);
1963
+ throw invalidInput(`--${field} must be a positive integer`, field, value);
1964
+ }
1965
+ function handleCommanderError(error) {
1966
+ if (error.code === "commander.helpDisplayed") {
1967
+ process.exit(error.exitCode);
1968
+ }
1969
+ exitWithAgentError(invalidInput(error.message, "command"));
1970
+ }
1971
+ function configureAgentParser(command) {
1972
+ command.configureOutput({
1973
+ writeErr: () => {
1974
+ },
1975
+ writeOut: (str) => {
1976
+ process.stdout.write(str);
1977
+ }
1978
+ });
1979
+ command.exitOverride(handleCommanderError);
1980
+ return command;
1981
+ }
1982
+ function parseWhere(value) {
1983
+ if (value == null) return void 0;
1984
+ try {
1985
+ const parsed = JSON.parse(value);
1986
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
1987
+ return parsed;
1988
+ }
1989
+ } catch {
1990
+ throw invalidInput("--where must be a JSON object", "where", value);
1991
+ }
1992
+ throw invalidInput("--where must be a JSON object", "where", value);
1993
+ }
1994
+ function buildAgentManifest() {
1995
+ const collections = {};
1996
+ for (const collection of COLLECTIONS3) {
1997
+ collections[collection] = {
1998
+ operations: ["query", "get"],
1999
+ fields: buildStableAgentFields()
2000
+ };
2001
+ }
2002
+ return {
2003
+ version: AGENT_PROTOCOL_VERSION,
2004
+ collections
2005
+ };
2006
+ }
2007
+ function validateAgentCollection(collection) {
2008
+ try {
2009
+ return validateCollection(collection);
2010
+ } catch (error) {
2011
+ const message = error instanceof Error ? error.message : `Unknown collection "${collection}".`;
2012
+ throw invalidInput(message, "collection", collection);
2013
+ }
2014
+ }
2015
+ function registerAgentCommands(program2, getClient2) {
2016
+ const agent = configureAgentParser(
2017
+ program2.command("agent").description("Machine-stable CLI namespace for coding agents").addHelpText(
2018
+ "after",
2019
+ "\nContract: docs/agent-cli-contract.md\nJSON only on stdout; no TTY effects."
2020
+ )
2021
+ );
2022
+ configureAgentParser(
2023
+ agent.command("manifest").description("Print the Agent CLI protocol manifest").option("--pretty", "Print 2-space indented JSON").action((opts) => {
2024
+ printAgentSuccess(buildAgentManifest(), { pretty: Boolean(opts.pretty) });
2025
+ })
2026
+ );
2027
+ configureAgentParser(
2028
+ agent.command("query <collection>").description("Query documents from a collection").option("--where <json>", "Filter conditions as a JSON object").option("--limit <n>", "Max results").option("--page <n>", "Page number").option("--sort <field>", "Sort field; prefix with - for descending").option("--select <fields>", "Comma-separated fields to select").option("--pretty", "Print 2-space indented JSON").action(
2029
+ async (collection, opts) => {
2030
+ try {
2031
+ const col = validateAgentCollection(collection);
2032
+ const options = {};
2033
+ const where = parseWhere(opts.where);
2034
+ const limit = parsePositiveInteger(opts.limit, "limit");
2035
+ const page = parsePositiveInteger(opts.page, "page");
2036
+ if (where) options.where = where;
2037
+ if (limit != null) options.limit = limit;
2038
+ if (page != null) options.page = page;
2039
+ if (opts.sort) options.sort = opts.sort;
2040
+ if (opts.select) options.select = parseSelect(opts.select);
2041
+ const client = getClient2();
2042
+ const result = await client.collections.from(col).find(options);
2043
+ printAgentSuccess(result, { pretty: Boolean(opts.pretty) });
2044
+ } catch (error) {
2045
+ exitWithAgentError(error, { pretty: Boolean(opts.pretty) });
2046
+ }
2047
+ }
2048
+ )
2049
+ );
2050
+ configureAgentParser(
2051
+ agent.command("get <collection> [id]").description("Get a document by ID").option("--select <fields>", "Comma-separated fields to select").option("--pretty", "Print 2-space indented JSON").action(
2052
+ async (collection, id, opts) => {
2053
+ try {
2054
+ const col = validateAgentCollection(collection);
2055
+ if (!id) {
2056
+ throw invalidInput("Missing required argument: id", "id");
2057
+ }
2058
+ const options = {};
2059
+ if (opts.select) options.select = parseSelect(opts.select);
2060
+ const client = getClient2();
2061
+ const result = await client.collections.from(col).findById(id, options);
2062
+ printAgentSuccess(result, { pretty: Boolean(opts.pretty) });
2063
+ } catch (error) {
2064
+ exitWithAgentError(error, { pretty: Boolean(opts.pretty) });
2065
+ }
2066
+ }
2067
+ )
2068
+ );
2069
+ }
2070
+
1853
2071
  // src/index.ts
1854
2072
  var require2 = createRequire(import.meta.url);
1855
2073
  var { version } = require2("../package.json");
@@ -1865,6 +2083,8 @@ process.on("unhandledRejection", (err) => {
1865
2083
  exitWithError(err, { format: getFormat() });
1866
2084
  });
1867
2085
  var getClient = () => resolveClient(program.opts().apiKey);
2086
+ var getAgentClient = () => resolveClientOrThrow(program.opts().apiKey);
2087
+ registerAgentCommands(program, getAgentClient);
1868
2088
  registerCrudCommands(program, getClient, getFormat);
1869
2089
  registerOrderCommands(program, getClient, getFormat);
1870
2090
  registerReturnCommands(program, getClient, getFormat);