@hardfin/cli 0.0.2-dev.11 → 0.0.2-dev.13

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 +44 -3
  2. package/dist/cli.js +1732 -88
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -2,8 +2,8 @@
2
2
  import { createRequire } from "node:module";
3
3
  import { Command, Option } from "commander";
4
4
  import { z } from "zod";
5
- import { chmodSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, renameSync, rmSync, statSync, writeFileSync, writeSync } from "node:fs";
6
- import { dirname, join, resolve } from "node:path";
5
+ import { chmodSync, closeSync, existsSync, mkdirSync, openAsBlob, openSync, readFileSync, renameSync, rmSync, statSync, writeFileSync, writeSync } from "node:fs";
6
+ import { basename, dirname, join, resolve } from "node:path";
7
7
  import { arch, cpus, homedir, release, totalmem, type, version } from "node:os";
8
8
  import { spawn, spawnSync } from "node:child_process";
9
9
  import { createServer } from "node:http";
@@ -198,24 +198,34 @@ function toGuide(commands, version) {
198
198
  "## Commands",
199
199
  ""
200
200
  ];
201
- for (const command of commands) {
202
- lines.push(`### \`hardfin ${command.name}\``, "", command.description ?? command.summary, "");
203
- if (command.arguments.length > 0) {
204
- lines.push("| Argument | Required | Holds |", "| --- | --- | --- |");
205
- for (const argument of command.arguments) lines.push(`| \`${argument.name}\` | ${argument.required ? "yes" : "no"} | ${argument.description} |`);
206
- lines.push("");
207
- }
208
- if (command.flags.length > 0) {
209
- lines.push("| Flag | Takes | Does |", "| --- | --- | --- |");
210
- for (const flag of command.flags) {
211
- const name = flag.short ? `-${flag.short}, --${flag.name}` : `--${flag.name}`;
212
- lines.push(`| \`${name}\` | ${flag.valueName ?? "nothing"} | ${flag.description} |`);
213
- }
214
- lines.push("");
201
+ for (const command of commands.filter((command) => !command.hidden)) lines.push(...toCommandLines(command, []));
202
+ return lines.join("\n");
203
+ }
204
+ /** toCommandLines describes one command and everything nested under it. */
205
+ function toCommandLines(command, parents) {
206
+ const path = [...parents, command.name];
207
+ const lines = [
208
+ `### \`hardfin ${path.join(" ")}\``,
209
+ "",
210
+ command.description ?? command.summary,
211
+ ""
212
+ ];
213
+ if (command.arguments.length > 0) {
214
+ lines.push("| Argument | Required | Holds |", "| --- | --- | --- |");
215
+ for (const argument of command.arguments) lines.push(`| \`${argument.name}\` | ${argument.required ? "yes" : "no"} | ${argument.description} |`);
216
+ lines.push("");
217
+ }
218
+ if (command.flags.length > 0) {
219
+ lines.push("| Flag | Takes | Does |", "| --- | --- | --- |");
220
+ for (const flag of command.flags) {
221
+ const name = flag.short ? `-${flag.short}, --${flag.name}` : `--${flag.name}`;
222
+ lines.push(`| \`${name}\` | ${flag.valueName ?? "nothing"} | ${flag.description} |`);
215
223
  }
216
- for (const example of command.examples) lines.push(`${example.description}:`, "", "```sh", example.command, "```", "");
224
+ lines.push("");
217
225
  }
218
- return lines.join("\n");
226
+ for (const example of command.examples) lines.push(`${example.description}:`, "", "```sh", example.command, "```", "");
227
+ for (const subcommand of command.subcommands ?? []) lines.push(...toCommandLines(subcommand, path));
228
+ return lines;
219
229
  }
220
230
  async function runAgentGuide(input) {
221
231
  if (input.flags["json"] === true) {
@@ -604,11 +614,11 @@ async function request(options) {
604
614
  "X-API-Version": API_VERSION,
605
615
  Accept: "application/json"
606
616
  };
607
- if (options.body !== void 0) headers["Content-Type"] = "application/json";
617
+ if (options.body !== void 0 && options.form === void 0) headers["Content-Type"] = "application/json";
608
618
  const response = await fetch(url, {
609
619
  method: options.method,
610
620
  headers,
611
- body: options.body === void 0 ? void 0 : JSON.stringify(options.body)
621
+ body: options.form ?? (options.body === void 0 ? void 0 : JSON.stringify(options.body))
612
622
  });
613
623
  const envelope = toEnvelope(await response.text());
614
624
  if (!response.ok && envelope === void 0) throw new RequestFailure(response.status, [{
@@ -761,6 +771,132 @@ function toBody$1(source) {
761
771
  }
762
772
  }
763
773
  //#endregion
774
+ //#region src/command/completion.ts
775
+ const SHELLS = [
776
+ "bash",
777
+ "zsh",
778
+ "fish",
779
+ "powershell"
780
+ ];
781
+ const completionCommand = defineCommand({
782
+ name: "completion",
783
+ summary: "Print the shell script that completes hardfin commands",
784
+ description: "Writes a script for your shell. The script asks this CLI what may follow what you have typed, so completions never fall behind the commands.",
785
+ arguments: [{
786
+ name: "shell",
787
+ description: `The shell to write for: ${SHELLS.join(", ")}`,
788
+ required: true
789
+ }],
790
+ flags: [],
791
+ examples: [
792
+ {
793
+ description: "Complete in this shell, now",
794
+ command: "source <(hardfin completion zsh)"
795
+ },
796
+ {
797
+ description: "Complete in every new shell",
798
+ command: "hardfin completion zsh > ~/.hardfin-completion.zsh"
799
+ },
800
+ {
801
+ description: "Complete in bash",
802
+ command: "source <(hardfin completion bash)"
803
+ }
804
+ ],
805
+ run: runCompletion
806
+ });
807
+ /** The hidden command a completion script asks, which keeps one implementation for every shell. */
808
+ const completeCommand = defineCommand({
809
+ name: "__complete",
810
+ summary: "Answer what may follow the words typed so far",
811
+ hidden: true,
812
+ arguments: [{
813
+ name: "words",
814
+ description: "The words typed so far",
815
+ required: false,
816
+ variadic: true
817
+ }],
818
+ flags: [{
819
+ name: "json",
820
+ description: "Accepted for consistency, and ignored",
821
+ schema: z.boolean()
822
+ }],
823
+ examples: [],
824
+ run: async (input) => {
825
+ writeData(toCandidates(input.commands, input.args).join("\n"));
826
+ return ExitCode.OK;
827
+ }
828
+ });
829
+ /**
830
+ * toCandidates answers what may follow the words typed so far. A word starting with a dash
831
+ * asks for the current command's flags, and anything else asks for its subcommands.
832
+ */
833
+ function toCandidates(commands, words) {
834
+ const partial = words[words.length - 1] ?? "";
835
+ const walked = toWalked(commands, words.slice(0, -1));
836
+ if (partial.startsWith("-")) return toFlagNames(walked.command).filter((name) => name.startsWith(partial));
837
+ if (walked.isUnknown) return [];
838
+ return (walked.command?.subcommands ?? walked.remaining).map((command) => command.name).filter((name) => !name.startsWith("__")).filter((name) => name.startsWith(partial));
839
+ }
840
+ function toWalked(commands, words) {
841
+ let remaining = commands;
842
+ let command;
843
+ for (const word of words) {
844
+ if (word.startsWith("-") || command?.arguments.length) continue;
845
+ const found = remaining.find((entry) => entry.name === word);
846
+ if (!found) return {
847
+ command,
848
+ remaining,
849
+ isUnknown: true
850
+ };
851
+ command = found;
852
+ remaining = found.subcommands ?? [];
853
+ }
854
+ return {
855
+ command,
856
+ remaining,
857
+ isUnknown: false
858
+ };
859
+ }
860
+ function toFlagNames(command) {
861
+ return [...(command?.flags ?? []).map((flag) => `--${flag.name}`), "--help"];
862
+ }
863
+ async function runCompletion(input) {
864
+ const shell = String(input.args[0] ?? "");
865
+ if (!SHELLS.includes(shell)) {
866
+ writeFailure(`${shell || "no shell"} is not one this CLI writes for. Choose ${SHELLS.join(", ")}`, input.isJSON);
867
+ return ExitCode.USAGE;
868
+ }
869
+ writeData(toScript(shell));
870
+ return ExitCode.OK;
871
+ }
872
+ /** toScript writes a shell's completion, each one asking __complete for the candidates. */
873
+ function toScript(shell) {
874
+ if (shell === "bash") return `# hardfin completion for bash
875
+ _hardfin_complete() {
876
+ local words
877
+ words=("\${COMP_WORDS[@]:1}")
878
+ COMPREPLY=($(hardfin __complete -- "\${words[@]}" 2>/dev/null))
879
+ }
880
+ complete -F _hardfin_complete hardfin`;
881
+ if (shell === "zsh") return `# hardfin completion for zsh
882
+ _hardfin_complete() {
883
+ local -a candidates
884
+ candidates=(\${(f)"$(hardfin __complete -- \${words[2,-1]} 2>/dev/null)"})
885
+ compadd -a candidates
886
+ }
887
+ compdef _hardfin_complete hardfin`;
888
+ if (shell === "fish") return `# hardfin completion for fish
889
+ complete -c hardfin -f -a "(hardfin __complete -- (commandline -opc)[2..-1] 2>/dev/null)"`;
890
+ return `# hardfin completion for PowerShell
891
+ Register-ArgumentCompleter -Native -CommandName hardfin -ScriptBlock {
892
+ param($wordToComplete, $commandAst, $cursorPosition)
893
+ $words = $commandAst.CommandElements | Select-Object -Skip 1 | ForEach-Object { $_.ToString() }
894
+ hardfin __complete -- @words 2>$null | ForEach-Object {
895
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
896
+ }
897
+ }`;
898
+ }
899
+ //#endregion
764
900
  //#region src/command/config.ts
765
901
  const configCommand = defineCommand({
766
902
  name: "config",
@@ -1496,10 +1632,17 @@ async function runMcp(input) {
1496
1632
  }
1497
1633
  //#endregion
1498
1634
  //#region src/command/operation.ts
1499
- const INPUT_FLAG = {
1500
- name: "input",
1501
- description: "A file holding the JSON request body, or - for stdin",
1502
- valueName: "file",
1635
+ const UNSET_FLAG = {
1636
+ name: "unset",
1637
+ description: "A field to clear, named as its flag is, repeatable",
1638
+ valueName: "field",
1639
+ repeatable: true,
1640
+ schema: z.array(z.string())
1641
+ };
1642
+ const FILE_FLAG = {
1643
+ name: "file",
1644
+ description: "The file to upload",
1645
+ valueName: "path",
1503
1646
  schema: z.string()
1504
1647
  };
1505
1648
  const JSON_FLAG = {
@@ -1509,15 +1652,27 @@ const JSON_FLAG = {
1509
1652
  };
1510
1653
  /** defineOperation turns one endpoint into the command that calls it. */
1511
1654
  function defineOperation(operation) {
1512
- const flags = [...operation.queryFlags, JSON_FLAG];
1513
- if (operation.takesBody) flags.splice(flags.length - 1, 0, INPUT_FLAG);
1655
+ const flags = [
1656
+ ...operation.queryFlags,
1657
+ ...operation.bodyFlags,
1658
+ ...operation.bodyFlags.some((flag) => flag.nullable) ? [UNSET_FLAG] : [],
1659
+ ...operation.upload ? [...operation.upload.fields, FILE_FLAG] : [],
1660
+ JSON_FLAG
1661
+ ];
1514
1662
  return {
1515
1663
  name: operation.name,
1516
1664
  summary: operation.summary,
1517
1665
  description: operation.description ?? operation.summary,
1518
1666
  arguments: operation.pathParameters,
1519
1667
  flags,
1520
- examples: [],
1668
+ examples: operation.example ? [{
1669
+ description: operation.summary,
1670
+ command: operation.example
1671
+ }] : [],
1672
+ endpoint: {
1673
+ method: operation.method,
1674
+ path: operation.path
1675
+ },
1521
1676
  run: (input) => runOperation(operation, input)
1522
1677
  };
1523
1678
  }
@@ -1527,13 +1682,24 @@ async function runOperation(operation, input) {
1527
1682
  writeFailure(`this command takes ${operation.pathParameters.length} argument(s)`, input.isJSON);
1528
1683
  return ExitCode.USAGE;
1529
1684
  }
1530
- let body;
1531
- if (typeof input.flags["input"] === "string") {
1532
- body = toBody(input.flags["input"]);
1533
- if (body === void 0) {
1534
- writeFailure(`${input.flags["input"]} does not hold JSON`, input.isJSON);
1685
+ const missing = operation.bodyFlags.concat(operation.upload?.fields ?? []).filter((flag) => flag.required && input.flags[toOptionKey(flag.name)] === void 0);
1686
+ if (missing.length > 0) {
1687
+ writeFailure(`this command needs ${missing.map((flag) => `--${flag.name}`).join(", ")}`, input.isJSON);
1688
+ return ExitCode.USAGE;
1689
+ }
1690
+ const body = toBody(operation, input.flags);
1691
+ if (body instanceof Error) {
1692
+ writeFailure(body.message, input.isJSON);
1693
+ return ExitCode.USAGE;
1694
+ }
1695
+ let form;
1696
+ if (operation.upload) {
1697
+ const built = await toForm(operation.upload, input.flags);
1698
+ if (built instanceof Error) {
1699
+ writeFailure(built.message, input.isJSON);
1535
1700
  return ExitCode.USAGE;
1536
1701
  }
1702
+ form = built;
1537
1703
  }
1538
1704
  try {
1539
1705
  writeData((await request({
@@ -1542,7 +1708,8 @@ async function runOperation(operation, input) {
1542
1708
  method: operation.method,
1543
1709
  path,
1544
1710
  query: toQuery(operation, input.flags),
1545
- body
1711
+ body,
1712
+ form
1546
1713
  })).data);
1547
1714
  return ExitCode.OK;
1548
1715
  } catch (error) {
@@ -1579,13 +1746,80 @@ function toQuery(operation, flags) {
1579
1746
  function toOptionKey(name) {
1580
1747
  return name.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
1581
1748
  }
1582
- function toBody(source) {
1583
- const text = source === "-" ? readFileSync(0, "utf8") : readFileSync(source, "utf8");
1749
+ /** toForm builds the file part and its fields, which an upload endpoint takes. */
1750
+ async function toForm(upload, flags) {
1751
+ const path = flags["file"];
1752
+ if (typeof path !== "string") return /* @__PURE__ */ new Error("this command needs --file, the file to upload");
1753
+ const form = new FormData();
1584
1754
  try {
1585
- return JSON.parse(text);
1755
+ form.append(upload.filePart, await openAsBlob(path), basename(path));
1586
1756
  } catch {
1587
- return;
1757
+ return /* @__PURE__ */ new Error(`${path} cannot be read`);
1758
+ }
1759
+ for (const field of upload.fields) {
1760
+ const value = flags[toOptionKey(field.name)];
1761
+ if (value !== void 0) form.append(field.jsonPath[0] ?? field.name, String(value));
1762
+ }
1763
+ return form;
1764
+ }
1765
+ /** toBody builds the request body from the flags, one field at a time. */
1766
+ function toBody(operation, flags) {
1767
+ const body = {};
1768
+ let hasField = false;
1769
+ for (const flag of operation.bodyFlags) {
1770
+ const value = flags[toOptionKey(flag.name)];
1771
+ if (value === void 0) continue;
1772
+ if (flag.element) {
1773
+ const elements = toElements(flag, Array.isArray(value) ? value.map(String) : [String(value)]);
1774
+ if (elements instanceof Error) return elements;
1775
+ set(body, flag.jsonPath, elements);
1776
+ hasField = true;
1777
+ continue;
1778
+ }
1779
+ const parsed = flag.schema.safeParse(value);
1780
+ set(body, flag.jsonPath, parsed.success ? parsed.data : value);
1781
+ hasField = true;
1588
1782
  }
1783
+ const cleared = toCleared(operation, flags, body);
1784
+ if (cleared instanceof Error) return cleared;
1785
+ return hasField || cleared ? body : void 0;
1786
+ }
1787
+ /** toCleared sends null for each field named by --unset, which is how a field is cleared. */
1788
+ function toCleared(operation, flags, body) {
1789
+ const named = flags["unset"];
1790
+ const names = Array.isArray(named) ? named.map(String) : named === void 0 ? [] : [String(named)];
1791
+ for (const name of names) {
1792
+ const flag = operation.bodyFlags.find((entry) => entry.name === name.replace(/^--/, ""));
1793
+ if (!flag) return /* @__PURE__ */ new Error(`--unset names no field called ${name}`);
1794
+ if (!flag.nullable) return /* @__PURE__ */ new Error(`--${flag.name} cannot be cleared, because the API does not accept null for it`);
1795
+ set(body, flag.jsonPath, null);
1796
+ }
1797
+ return names.length > 0;
1798
+ }
1799
+ /** toElements reads the key=value pairs a repeated flag carries for one array element. */
1800
+ function toElements(flag, values) {
1801
+ const elements = [];
1802
+ for (const value of values) {
1803
+ const element = {};
1804
+ for (const pair of value.split(",")) {
1805
+ const split = pair.indexOf("=");
1806
+ if (split < 1) return /* @__PURE__ */ new Error(`--${flag.name} takes ${flag.element?.join("=, ")}=, such as --${flag.name} ${flag.element?.[0]}=value`);
1807
+ const key = pair.slice(0, split);
1808
+ if (flag.element && !flag.element.includes(key)) return /* @__PURE__ */ new Error(`--${flag.name} has no field ${key}. It takes ${flag.element.join(", ")}`);
1809
+ element[key] = pair.slice(split + 1);
1810
+ }
1811
+ elements.push(element);
1812
+ }
1813
+ return elements;
1814
+ }
1815
+ /** set writes a value at its path, building the objects a nested field needs. */
1816
+ function set(body, path, value) {
1817
+ let holder = body;
1818
+ for (const name of path.slice(0, -1)) {
1819
+ holder[name] = holder[name] ?? {};
1820
+ holder = holder[name];
1821
+ }
1822
+ holder[path[path.length - 1] ?? ""] = value;
1589
1823
  }
1590
1824
  //#endregion
1591
1825
  //#region src/command/surface.generated.ts
@@ -1600,6 +1834,7 @@ const surfaceCommands = [
1600
1834
  defineOperation({
1601
1835
  name: "list",
1602
1836
  summary: "Get asset listing",
1837
+ example: "hardfin asset list --limit 10",
1603
1838
  method: "GET",
1604
1839
  path: "/asset",
1605
1840
  pathParameters: [],
@@ -1783,16 +2018,185 @@ const surfaceCommands = [
1783
2018
  ])
1784
2019
  }
1785
2020
  ],
1786
- takesBody: false
2021
+ bodyFlags: []
1787
2022
  }),
1788
2023
  defineOperation({
1789
2024
  name: "create",
1790
2025
  summary: "Create asset",
2026
+ example: "hardfin asset create --item-id <value> --serial <value>",
1791
2027
  method: "POST",
1792
2028
  path: "/asset",
1793
2029
  pathParameters: [],
1794
2030
  queryFlags: [],
1795
- takesBody: true
2031
+ bodyFlags: [
2032
+ {
2033
+ name: "allocated-indirect",
2034
+ jsonPath: ["allocatedIndirect"],
2035
+ description: "One unit's share of overhead, a cost component",
2036
+ valueName: "value",
2037
+ nullable: true,
2038
+ schema: z.string()
2039
+ },
2040
+ {
2041
+ name: "bill-of-materials",
2042
+ jsonPath: ["billOfMaterials"],
2043
+ description: "The parts cost of one unit, a cost component",
2044
+ valueName: "value",
2045
+ nullable: true,
2046
+ schema: z.string()
2047
+ },
2048
+ {
2049
+ name: "depreciation-model",
2050
+ jsonPath: ["depreciationModel"],
2051
+ description: "The method one unit is depreciated by, or null to clear it",
2052
+ valueName: "value",
2053
+ schema: z.enum([
2054
+ "DOUBLE_DECLINING",
2055
+ "STRAIGHT_LINE",
2056
+ "SUM_YEAR",
2057
+ "UNIT_OF_PRODUCTION"
2058
+ ])
2059
+ },
2060
+ {
2061
+ name: "description",
2062
+ jsonPath: ["description"],
2063
+ description: "A free-form description of the asset",
2064
+ valueName: "value",
2065
+ nullable: true,
2066
+ schema: z.string()
2067
+ },
2068
+ {
2069
+ name: "direct-labor",
2070
+ jsonPath: ["directLabor"],
2071
+ description: "The labor cost to build one unit, a cost component",
2072
+ valueName: "value",
2073
+ nullable: true,
2074
+ schema: z.string()
2075
+ },
2076
+ {
2077
+ name: "freight-inbound",
2078
+ jsonPath: ["freightInbound"],
2079
+ description: "The shipping cost to receive one unit, a cost component",
2080
+ valueName: "value",
2081
+ nullable: true,
2082
+ schema: z.string()
2083
+ },
2084
+ {
2085
+ name: "freight-outbound",
2086
+ jsonPath: ["freightOutbound"],
2087
+ description: "The shipping cost to deploy one unit, a deployment cost component",
2088
+ valueName: "value",
2089
+ nullable: true,
2090
+ schema: z.string()
2091
+ },
2092
+ {
2093
+ name: "functional-status",
2094
+ jsonPath: ["functionalStatus"],
2095
+ description: "The asset's starting functional status, FUNCTIONAL when absent, which cannot be SCRAPPED",
2096
+ valueName: "value",
2097
+ nullable: true,
2098
+ schema: z.enum([
2099
+ "FUNCTIONAL",
2100
+ "NEEDS_REVIEW",
2101
+ "NON-FUNCTIONAL",
2102
+ "SCRAPPED"
2103
+ ])
2104
+ },
2105
+ {
2106
+ name: "in-inventory-date",
2107
+ jsonPath: ["inInventoryDate"],
2108
+ description: "The day the asset entered inventory, which cannot be in the future",
2109
+ valueName: "value",
2110
+ schema: z.string()
2111
+ },
2112
+ {
2113
+ name: "in-service-date",
2114
+ jsonPath: ["inServiceDate"],
2115
+ description: "The day the asset was put into service, which Hardfin sets itself when absent",
2116
+ valueName: "value",
2117
+ nullable: true,
2118
+ schema: z.string()
2119
+ },
2120
+ {
2121
+ name: "installation",
2122
+ jsonPath: ["installation"],
2123
+ description: "The cost to install one unit, a deployment cost component",
2124
+ valueName: "value",
2125
+ nullable: true,
2126
+ schema: z.string()
2127
+ },
2128
+ {
2129
+ name: "interest",
2130
+ jsonPath: ["interest"],
2131
+ description: "The financing cost of one unit, a cost component",
2132
+ valueName: "value",
2133
+ nullable: true,
2134
+ schema: z.string()
2135
+ },
2136
+ {
2137
+ name: "item-id",
2138
+ jsonPath: ["itemId"],
2139
+ description: "The ID of the catalog item the asset is a unit of",
2140
+ valueName: "value",
2141
+ required: true,
2142
+ schema: z.string()
2143
+ },
2144
+ {
2145
+ name: "location-id",
2146
+ jsonPath: ["locationId"],
2147
+ description: "The ID of the location the asset enters inventory at",
2148
+ valueName: "value",
2149
+ schema: z.string()
2150
+ },
2151
+ {
2152
+ name: "salvage-value",
2153
+ jsonPath: ["salvageValue"],
2154
+ description: "The value one unit keeps at the end of its useful life, or null to clear it",
2155
+ valueName: "value",
2156
+ nullable: true,
2157
+ schema: z.string()
2158
+ },
2159
+ {
2160
+ name: "serial",
2161
+ jsonPath: ["serial"],
2162
+ description: "The asset's serial number, unique within its item",
2163
+ valueName: "value",
2164
+ required: true,
2165
+ schema: z.string()
2166
+ },
2167
+ {
2168
+ name: "simple-cost-basis",
2169
+ jsonPath: ["simpleCostBasis"],
2170
+ description: "A single cost for one unit, which cannot be sent together with the cost components",
2171
+ valueName: "value",
2172
+ nullable: true,
2173
+ schema: z.string()
2174
+ },
2175
+ {
2176
+ name: "tariffs",
2177
+ jsonPath: ["tariffs"],
2178
+ description: "The import duty paid on one unit, a cost component",
2179
+ valueName: "value",
2180
+ nullable: true,
2181
+ schema: z.string()
2182
+ },
2183
+ {
2184
+ name: "tax",
2185
+ jsonPath: ["tax"],
2186
+ description: "The tax paid on one unit, a cost component",
2187
+ valueName: "value",
2188
+ nullable: true,
2189
+ schema: z.string()
2190
+ },
2191
+ {
2192
+ name: "useful-life",
2193
+ jsonPath: ["usefulLife"],
2194
+ description: "The number of months one unit is depreciated over, or null to clear it",
2195
+ valueName: "number",
2196
+ nullable: true,
2197
+ schema: z.coerce.number()
2198
+ }
2199
+ ]
1796
2200
  }),
1797
2201
  {
1798
2202
  name: "move",
@@ -1809,11 +2213,28 @@ const surfaceCommands = [
1809
2213
  subcommands: [defineOperation({
1810
2214
  name: "create",
1811
2215
  summary: "Execute asset move",
2216
+ example: "hardfin asset move execute create",
1812
2217
  method: "POST",
1813
2218
  path: "/asset/move/execute",
1814
2219
  pathParameters: [],
1815
2220
  queryFlags: [],
1816
- takesBody: true
2221
+ bodyFlags: [{
2222
+ name: "move",
2223
+ jsonPath: ["moves"],
2224
+ description: "The moves to carry out",
2225
+ valueName: "assetId=,deliverAt=",
2226
+ repeatable: true,
2227
+ element: [
2228
+ "assetId",
2229
+ "deliverAt",
2230
+ "deliverAtTimezone",
2231
+ "destinationId",
2232
+ "originId",
2233
+ "shipAt",
2234
+ "shipAtTimezone"
2235
+ ],
2236
+ schema: z.array(z.string())
2237
+ }]
1817
2238
  })]
1818
2239
  }, {
1819
2240
  name: "plan",
@@ -1824,17 +2245,32 @@ const surfaceCommands = [
1824
2245
  subcommands: [defineOperation({
1825
2246
  name: "create",
1826
2247
  summary: "Plan asset move",
2248
+ example: "hardfin asset move plan create",
1827
2249
  method: "POST",
1828
2250
  path: "/asset/move/plan",
1829
2251
  pathParameters: [],
1830
2252
  queryFlags: [],
1831
- takesBody: true
2253
+ bodyFlags: [{
2254
+ name: "move",
2255
+ jsonPath: ["moves"],
2256
+ description: "The moves to plan",
2257
+ valueName: "assetId=,deliverAt=",
2258
+ repeatable: true,
2259
+ element: [
2260
+ "assetId",
2261
+ "deliverAt",
2262
+ "id",
2263
+ "shipAt"
2264
+ ],
2265
+ schema: z.array(z.string())
2266
+ }]
1832
2267
  })]
1833
2268
  }]
1834
2269
  },
1835
2270
  defineOperation({
1836
2271
  name: "get",
1837
2272
  summary: "Get asset",
2273
+ example: "hardfin asset get ast_4f9xk2mq7plr8stz",
1838
2274
  method: "GET",
1839
2275
  path: "/asset/{assetKey}",
1840
2276
  pathParameters: [{
@@ -1843,11 +2279,12 @@ const surfaceCommands = [
1843
2279
  required: true
1844
2280
  }],
1845
2281
  queryFlags: [],
1846
- takesBody: false
2282
+ bodyFlags: []
1847
2283
  }),
1848
2284
  defineOperation({
1849
2285
  name: "update",
1850
2286
  summary: "Patch asset",
2287
+ example: "hardfin asset update ast_4f9xk2mq7plr8stz",
1851
2288
  method: "PATCH",
1852
2289
  path: "/asset/{assetKey}",
1853
2290
  pathParameters: [{
@@ -1856,7 +2293,62 @@ const surfaceCommands = [
1856
2293
  required: true
1857
2294
  }],
1858
2295
  queryFlags: [],
1859
- takesBody: true
2296
+ bodyFlags: [
2297
+ {
2298
+ name: "description",
2299
+ jsonPath: ["description"],
2300
+ description: "The asset's new description, or null to clear it",
2301
+ valueName: "value",
2302
+ nullable: true,
2303
+ schema: z.string()
2304
+ },
2305
+ {
2306
+ name: "functional-status",
2307
+ jsonPath: ["functionalStatus"],
2308
+ description: "The asset's new functional status, which cannot be SCRAPPED because scrapping has its own endpoint",
2309
+ valueName: "value",
2310
+ nullable: true,
2311
+ schema: z.enum([
2312
+ "FUNCTIONAL",
2313
+ "NEEDS_REVIEW",
2314
+ "NON-FUNCTIONAL",
2315
+ "SCRAPPED"
2316
+ ])
2317
+ },
2318
+ {
2319
+ name: "in-inventory-date",
2320
+ jsonPath: ["inInventoryDate"],
2321
+ description: "The day the asset entered inventory, which cannot be in the future",
2322
+ valueName: "value",
2323
+ nullable: true,
2324
+ schema: z.string()
2325
+ },
2326
+ {
2327
+ name: "initial-location-id",
2328
+ jsonPath: ["initialLocationId"],
2329
+ description: "The ID of the location the asset entered inventory at",
2330
+ valueName: "value",
2331
+ nullable: true,
2332
+ schema: z.string()
2333
+ },
2334
+ {
2335
+ name: "metadata",
2336
+ jsonPath: ["metadata"],
2337
+ description: "New values for the asset's custom fields, each naming its field",
2338
+ valueName: "fieldId=,value=",
2339
+ repeatable: true,
2340
+ element: ["fieldId", "value"],
2341
+ schema: z.array(z.string())
2342
+ },
2343
+ {
2344
+ name: "serial",
2345
+ jsonPath: ["serial"],
2346
+ description: "The asset's new serial number, which cannot be empty",
2347
+ valueName: "value",
2348
+ nullable: true,
2349
+ schema: z.string()
2350
+ }
2351
+ ]
1860
2352
  }),
1861
2353
  {
1862
2354
  name: "accounting",
@@ -1867,6 +2359,7 @@ const surfaceCommands = [
1867
2359
  subcommands: [defineOperation({
1868
2360
  name: "update",
1869
2361
  summary: "Update asset accounting",
2362
+ example: "hardfin asset accounting update ast_4f9xk2mq7plr8stz",
1870
2363
  method: "PATCH",
1871
2364
  path: "/asset/{assetKey}/accounting",
1872
2365
  pathParameters: [{
@@ -1875,7 +2368,131 @@ const surfaceCommands = [
1875
2368
  required: true
1876
2369
  }],
1877
2370
  queryFlags: [],
1878
- takesBody: true
2371
+ bodyFlags: [
2372
+ {
2373
+ name: "allocated-indirect",
2374
+ jsonPath: ["allocatedIndirect"],
2375
+ description: "One unit's share of overhead, a cost component",
2376
+ valueName: "value",
2377
+ nullable: true,
2378
+ schema: z.string()
2379
+ },
2380
+ {
2381
+ name: "bill-of-materials",
2382
+ jsonPath: ["billOfMaterials"],
2383
+ description: "The parts cost of one unit, a cost component",
2384
+ valueName: "value",
2385
+ nullable: true,
2386
+ schema: z.string()
2387
+ },
2388
+ {
2389
+ name: "depreciation-model",
2390
+ jsonPath: ["depreciationModel"],
2391
+ description: "The method one unit is depreciated by, or null to clear it",
2392
+ valueName: "value",
2393
+ schema: z.enum([
2394
+ "DOUBLE_DECLINING",
2395
+ "STRAIGHT_LINE",
2396
+ "SUM_YEAR",
2397
+ "UNIT_OF_PRODUCTION"
2398
+ ])
2399
+ },
2400
+ {
2401
+ name: "direct-labor",
2402
+ jsonPath: ["directLabor"],
2403
+ description: "The labor cost to build one unit, a cost component",
2404
+ valueName: "value",
2405
+ nullable: true,
2406
+ schema: z.string()
2407
+ },
2408
+ {
2409
+ name: "freight-inbound",
2410
+ jsonPath: ["freightInbound"],
2411
+ description: "The shipping cost to receive one unit, a cost component",
2412
+ valueName: "value",
2413
+ nullable: true,
2414
+ schema: z.string()
2415
+ },
2416
+ {
2417
+ name: "freight-outbound",
2418
+ jsonPath: ["freightOutbound"],
2419
+ description: "The shipping cost to deploy one unit, a deployment cost component",
2420
+ valueName: "value",
2421
+ nullable: true,
2422
+ schema: z.string()
2423
+ },
2424
+ {
2425
+ name: "in-service-date",
2426
+ jsonPath: ["inServiceDate"],
2427
+ description: "The day the asset was put into service and began depreciating, or null to clear it",
2428
+ valueName: "value",
2429
+ nullable: true,
2430
+ schema: z.string()
2431
+ },
2432
+ {
2433
+ name: "installation",
2434
+ jsonPath: ["installation"],
2435
+ description: "The cost to install one unit, a deployment cost component",
2436
+ valueName: "value",
2437
+ nullable: true,
2438
+ schema: z.string()
2439
+ },
2440
+ {
2441
+ name: "interest",
2442
+ jsonPath: ["interest"],
2443
+ description: "The financing cost of one unit, a cost component",
2444
+ valueName: "value",
2445
+ nullable: true,
2446
+ schema: z.string()
2447
+ },
2448
+ {
2449
+ name: "is-in-service-date-managed-automatically",
2450
+ jsonPath: ["isInServiceDateManagedAutomatically"],
2451
+ description: "Whether Hardfin sets the in-service date itself, which sending an in-service date turns off",
2452
+ nullable: true,
2453
+ schema: z.boolean()
2454
+ },
2455
+ {
2456
+ name: "salvage-value",
2457
+ jsonPath: ["salvageValue"],
2458
+ description: "The value one unit keeps at the end of its useful life, or null to clear it",
2459
+ valueName: "value",
2460
+ nullable: true,
2461
+ schema: z.string()
2462
+ },
2463
+ {
2464
+ name: "simple-cost-basis",
2465
+ jsonPath: ["simpleCostBasis"],
2466
+ description: "A single cost for one unit, which cannot be sent together with the cost components",
2467
+ valueName: "value",
2468
+ nullable: true,
2469
+ schema: z.string()
2470
+ },
2471
+ {
2472
+ name: "tariffs",
2473
+ jsonPath: ["tariffs"],
2474
+ description: "The import duty paid on one unit, a cost component",
2475
+ valueName: "value",
2476
+ nullable: true,
2477
+ schema: z.string()
2478
+ },
2479
+ {
2480
+ name: "tax",
2481
+ jsonPath: ["tax"],
2482
+ description: "The tax paid on one unit, a cost component",
2483
+ valueName: "value",
2484
+ nullable: true,
2485
+ schema: z.string()
2486
+ },
2487
+ {
2488
+ name: "useful-life",
2489
+ jsonPath: ["usefulLife"],
2490
+ description: "The number of months one unit is depreciated over, or null to clear it",
2491
+ valueName: "number",
2492
+ nullable: true,
2493
+ schema: z.coerce.number()
2494
+ }
2495
+ ]
1879
2496
  }), {
1880
2497
  name: "in-service-management",
1881
2498
  summary: "In service management commands",
@@ -1885,6 +2502,7 @@ const surfaceCommands = [
1885
2502
  subcommands: [defineOperation({
1886
2503
  name: "update",
1887
2504
  summary: "Toggle in service date management",
2505
+ example: "hardfin asset accounting in-service-management update ast_4f9xk2mq7plr8stz --automatic <value>",
1888
2506
  method: "PATCH",
1889
2507
  path: "/asset/{assetKey}/accounting/in-service-management",
1890
2508
  pathParameters: [{
@@ -1893,7 +2511,13 @@ const surfaceCommands = [
1893
2511
  required: true
1894
2512
  }],
1895
2513
  queryFlags: [],
1896
- takesBody: true
2514
+ bodyFlags: [{
2515
+ name: "automatic",
2516
+ jsonPath: ["automatic"],
2517
+ description: "Whether Hardfin sets the asset's in-service date itself",
2518
+ required: true,
2519
+ schema: z.boolean()
2520
+ }]
1897
2521
  })]
1898
2522
  }]
1899
2523
  },
@@ -1906,6 +2530,7 @@ const surfaceCommands = [
1906
2530
  subcommands: [defineOperation({
1907
2531
  name: "create",
1908
2532
  summary: "Create asset cost adjustment",
2533
+ example: "hardfin asset cost-adjustment create ast_4f9xk2mq7plr8stz --adjustment-type <value> --amount <value> --effective-date <value>",
1909
2534
  method: "POST",
1910
2535
  path: "/asset/{assetKey}/cost-adjustment",
1911
2536
  pathParameters: [{
@@ -1914,7 +2539,58 @@ const surfaceCommands = [
1914
2539
  required: true
1915
2540
  }],
1916
2541
  queryFlags: [],
1917
- takesBody: true
2542
+ bodyFlags: [
2543
+ {
2544
+ name: "adjustment-type",
2545
+ jsonPath: ["adjustmentType"],
2546
+ description: "Whether the adjustment adds to the asset's cost basis or writes it down",
2547
+ valueName: "value",
2548
+ required: true,
2549
+ schema: z.enum(["CAPITALIZATION", "IMPAIRMENT"])
2550
+ },
2551
+ {
2552
+ name: "amount",
2553
+ jsonPath: ["amount"],
2554
+ description: "How much the adjustment changes the cost basis by, which must be greater than zero",
2555
+ valueName: "value",
2556
+ required: true,
2557
+ schema: z.string()
2558
+ },
2559
+ {
2560
+ name: "effective-date",
2561
+ jsonPath: ["effectiveDate"],
2562
+ description: "The day the adjustment takes effect, which cannot be in the future",
2563
+ valueName: "value",
2564
+ required: true,
2565
+ schema: z.string()
2566
+ },
2567
+ {
2568
+ name: "notes",
2569
+ jsonPath: ["notes"],
2570
+ description: "Free-form detail about the adjustment, which a reason of OTHER requires",
2571
+ valueName: "value",
2572
+ nullable: true,
2573
+ schema: z.string()
2574
+ },
2575
+ {
2576
+ name: "reason",
2577
+ jsonPath: ["reason"],
2578
+ description: "Why the adjustment was made, which must be one its adjustment type allows",
2579
+ valueName: "value",
2580
+ required: true,
2581
+ schema: z.enum([
2582
+ "ADDITION",
2583
+ "BETTERMENT",
2584
+ "DAMAGE",
2585
+ "INSTALLATION",
2586
+ "LIFE_EXTENSION",
2587
+ "MARKET_DECLINE",
2588
+ "OBSOLESCENCE",
2589
+ "OTHER",
2590
+ "REGULATORY"
2591
+ ])
2592
+ }
2593
+ ]
1918
2594
  })]
1919
2595
  },
1920
2596
  {
@@ -1926,6 +2602,7 @@ const surfaceCommands = [
1926
2602
  subcommands: [defineOperation({
1927
2603
  name: "list",
1928
2604
  summary: "Get asset event list",
2605
+ example: "hardfin asset event list ast_4f9xk2mq7plr8stz",
1929
2606
  method: "GET",
1930
2607
  path: "/asset/{assetKey}/event",
1931
2608
  pathParameters: [{
@@ -1934,7 +2611,7 @@ const surfaceCommands = [
1934
2611
  required: true
1935
2612
  }],
1936
2613
  queryFlags: [],
1937
- takesBody: false
2614
+ bodyFlags: []
1938
2615
  })]
1939
2616
  },
1940
2617
  {
@@ -1946,6 +2623,7 @@ const surfaceCommands = [
1946
2623
  subcommands: [defineOperation({
1947
2624
  name: "list",
1948
2625
  summary: "Get asset event group listing",
2626
+ example: "hardfin asset event-group list ast_4f9xk2mq7plr8stz",
1949
2627
  method: "GET",
1950
2628
  path: "/asset/{assetKey}/event-group",
1951
2629
  pathParameters: [{
@@ -1966,10 +2644,11 @@ const surfaceCommands = [
1966
2644
  valueName: "value",
1967
2645
  schema: z.string()
1968
2646
  }],
1969
- takesBody: false
2647
+ bodyFlags: []
1970
2648
  }), defineOperation({
1971
2649
  name: "get",
1972
2650
  summary: "Get asset event group",
2651
+ example: "hardfin asset event-group get ast_4f9xk2mq7plr8stz aeg_3mx8kq2plr7stz4w",
1973
2652
  method: "GET",
1974
2653
  path: "/asset/{assetKey}/event-group/{eventGroupKey}",
1975
2654
  pathParameters: [{
@@ -1982,7 +2661,7 @@ const surfaceCommands = [
1982
2661
  required: true
1983
2662
  }],
1984
2663
  queryFlags: [],
1985
- takesBody: false
2664
+ bodyFlags: []
1986
2665
  })]
1987
2666
  },
1988
2667
  {
@@ -1994,6 +2673,7 @@ const surfaceCommands = [
1994
2673
  subcommands: [defineOperation({
1995
2674
  name: "list",
1996
2675
  summary: "Get asset files",
2676
+ example: "hardfin asset file list ast_4f9xk2mq7plr8stz",
1997
2677
  method: "GET",
1998
2678
  path: "/asset/{assetKey}/file",
1999
2679
  pathParameters: [{
@@ -2002,10 +2682,11 @@ const surfaceCommands = [
2002
2682
  required: true
2003
2683
  }],
2004
2684
  queryFlags: [],
2005
- takesBody: false
2685
+ bodyFlags: []
2006
2686
  }), defineOperation({
2007
2687
  name: "delete",
2008
2688
  summary: "Delete asset file",
2689
+ example: "hardfin asset file delete ast_4f9xk2mq7plr8stz file_7hq2mx9pkr4stz8w",
2009
2690
  method: "DELETE",
2010
2691
  path: "/asset/{assetKey}/file/{fileKey}",
2011
2692
  pathParameters: [{
@@ -2018,7 +2699,7 @@ const surfaceCommands = [
2018
2699
  required: true
2019
2700
  }],
2020
2701
  queryFlags: [],
2021
- takesBody: false
2702
+ bodyFlags: []
2022
2703
  })]
2023
2704
  },
2024
2705
  {
@@ -2030,6 +2711,7 @@ const surfaceCommands = [
2030
2711
  subcommands: [defineOperation({
2031
2712
  name: "list",
2032
2713
  summary: "Get asset functional status history",
2714
+ example: "hardfin asset functional-status list ast_4f9xk2mq7plr8stz",
2033
2715
  method: "GET",
2034
2716
  path: "/asset/{assetKey}/functional-status",
2035
2717
  pathParameters: [{
@@ -2038,7 +2720,7 @@ const surfaceCommands = [
2038
2720
  required: true
2039
2721
  }],
2040
2722
  queryFlags: [],
2041
- takesBody: false
2723
+ bodyFlags: []
2042
2724
  })]
2043
2725
  },
2044
2726
  {
@@ -2051,6 +2733,7 @@ const surfaceCommands = [
2051
2733
  defineOperation({
2052
2734
  name: "list",
2053
2735
  summary: "Get asset ownership history",
2736
+ example: "hardfin asset ownership list ast_4f9xk2mq7plr8stz",
2054
2737
  method: "GET",
2055
2738
  path: "/asset/{assetKey}/ownership",
2056
2739
  pathParameters: [{
@@ -2059,11 +2742,12 @@ const surfaceCommands = [
2059
2742
  required: true
2060
2743
  }],
2061
2744
  queryFlags: [],
2062
- takesBody: false
2745
+ bodyFlags: []
2063
2746
  }),
2064
2747
  defineOperation({
2065
2748
  name: "create",
2066
2749
  summary: "Create asset ownership",
2750
+ example: "hardfin asset ownership create ast_4f9xk2mq7plr8stz --customer-id <value> --date <value>",
2067
2751
  method: "POST",
2068
2752
  path: "/asset/{assetKey}/ownership",
2069
2753
  pathParameters: [{
@@ -2072,11 +2756,37 @@ const surfaceCommands = [
2072
2756
  required: true
2073
2757
  }],
2074
2758
  queryFlags: [],
2075
- takesBody: true
2759
+ bodyFlags: [
2760
+ {
2761
+ name: "customer-id",
2762
+ jsonPath: ["customerId"],
2763
+ description: "The ID of the customer that takes ownership of the asset",
2764
+ valueName: "value",
2765
+ required: true,
2766
+ schema: z.string()
2767
+ },
2768
+ {
2769
+ name: "date",
2770
+ jsonPath: ["date"],
2771
+ description: "The day the customer takes ownership, which cannot be in the future",
2772
+ valueName: "value",
2773
+ required: true,
2774
+ schema: z.string()
2775
+ },
2776
+ {
2777
+ name: "sale-price",
2778
+ jsonPath: ["salePrice"],
2779
+ description: "What the customer paid for the asset, which cannot be negative",
2780
+ valueName: "value",
2781
+ nullable: true,
2782
+ schema: z.string()
2783
+ }
2784
+ ]
2076
2785
  }),
2077
2786
  defineOperation({
2078
2787
  name: "clear",
2079
2788
  summary: "Clear the ownership an asset holds today",
2789
+ example: "hardfin asset ownership clear ast_4f9xk2mq7plr8stz --date <value>",
2080
2790
  method: "DELETE",
2081
2791
  path: "/asset/{assetKey}/ownership",
2082
2792
  pathParameters: [{
@@ -2085,11 +2795,19 @@ const surfaceCommands = [
2085
2795
  required: true
2086
2796
  }],
2087
2797
  queryFlags: [],
2088
- takesBody: true
2798
+ bodyFlags: [{
2799
+ name: "date",
2800
+ jsonPath: ["date"],
2801
+ description: "The day your organization takes the asset back, which cannot be in the future",
2802
+ valueName: "value",
2803
+ required: true,
2804
+ schema: z.string()
2805
+ }]
2089
2806
  }),
2090
2807
  defineOperation({
2091
2808
  name: "get",
2092
2809
  summary: "Get asset ownership segment",
2810
+ example: "hardfin asset ownership get ast_4f9xk2mq7plr8stz aown_8kq2mx7plr4stz9w",
2093
2811
  method: "GET",
2094
2812
  path: "/asset/{assetKey}/ownership/{segmentKey}",
2095
2813
  pathParameters: [{
@@ -2102,11 +2820,12 @@ const surfaceCommands = [
2102
2820
  required: true
2103
2821
  }],
2104
2822
  queryFlags: [],
2105
- takesBody: false
2823
+ bodyFlags: []
2106
2824
  }),
2107
2825
  defineOperation({
2108
2826
  name: "update",
2109
2827
  summary: "Patch asset ownership segment",
2828
+ example: "hardfin asset ownership update ast_4f9xk2mq7plr8stz aown_8kq2mx7plr4stz9w",
2110
2829
  method: "PATCH",
2111
2830
  path: "/asset/{assetKey}/ownership/{segmentKey}",
2112
2831
  pathParameters: [{
@@ -2119,11 +2838,37 @@ const surfaceCommands = [
2119
2838
  required: true
2120
2839
  }],
2121
2840
  queryFlags: [],
2122
- takesBody: true
2841
+ bodyFlags: [
2842
+ {
2843
+ name: "customer-id",
2844
+ jsonPath: ["customerId"],
2845
+ description: "The ID of the customer that owned the asset during the segment",
2846
+ valueName: "value",
2847
+ nullable: true,
2848
+ schema: z.string()
2849
+ },
2850
+ {
2851
+ name: "date",
2852
+ jsonPath: ["date"],
2853
+ description: "The day the segment's owner took ownership, which cannot be in the future",
2854
+ valueName: "value",
2855
+ nullable: true,
2856
+ schema: z.string()
2857
+ },
2858
+ {
2859
+ name: "sale-price",
2860
+ jsonPath: ["salePrice"],
2861
+ description: "What the owner paid for the asset, which cannot be negative",
2862
+ valueName: "value",
2863
+ nullable: true,
2864
+ schema: z.string()
2865
+ }
2866
+ ]
2123
2867
  }),
2124
2868
  defineOperation({
2125
2869
  name: "delete",
2126
2870
  summary: "Delete asset ownership segment",
2871
+ example: "hardfin asset ownership delete ast_4f9xk2mq7plr8stz aown_8kq2mx7plr4stz9w",
2127
2872
  method: "DELETE",
2128
2873
  path: "/asset/{assetKey}/ownership/{segmentKey}",
2129
2874
  pathParameters: [{
@@ -2136,7 +2881,7 @@ const surfaceCommands = [
2136
2881
  required: true
2137
2882
  }],
2138
2883
  queryFlags: [],
2139
- takesBody: false
2884
+ bodyFlags: []
2140
2885
  })
2141
2886
  ]
2142
2887
  },
@@ -2149,6 +2894,7 @@ const surfaceCommands = [
2149
2894
  subcommands: [defineOperation({
2150
2895
  name: "create",
2151
2896
  summary: "Scrap asset",
2897
+ example: "hardfin asset scrap create ast_4f9xk2mq7plr8stz --disposal-date <value>",
2152
2898
  method: "POST",
2153
2899
  path: "/asset/{assetKey}/scrap",
2154
2900
  pathParameters: [{
@@ -2157,7 +2903,32 @@ const surfaceCommands = [
2157
2903
  required: true
2158
2904
  }],
2159
2905
  queryFlags: [],
2160
- takesBody: true
2906
+ bodyFlags: [
2907
+ {
2908
+ name: "disposal-date",
2909
+ jsonPath: ["disposalDate"],
2910
+ description: "The day the asset was scrapped",
2911
+ valueName: "value",
2912
+ required: true,
2913
+ schema: z.string()
2914
+ },
2915
+ {
2916
+ name: "disposal-price",
2917
+ jsonPath: ["disposalPrice"],
2918
+ description: "What the scrapped asset was sold for, or null when it was not sold",
2919
+ valueName: "value",
2920
+ nullable: true,
2921
+ schema: z.string()
2922
+ },
2923
+ {
2924
+ name: "disposal-reason",
2925
+ jsonPath: ["disposalReason"],
2926
+ description: "Why the asset was scrapped",
2927
+ valueName: "value",
2928
+ nullable: true,
2929
+ schema: z.string()
2930
+ }
2931
+ ]
2161
2932
  })]
2162
2933
  },
2163
2934
  {
@@ -2169,6 +2940,7 @@ const surfaceCommands = [
2169
2940
  subcommands: [defineOperation({
2170
2941
  name: "create",
2171
2942
  summary: "Unscrap asset",
2943
+ example: "hardfin asset unscrap create ast_4f9xk2mq7plr8stz",
2172
2944
  method: "POST",
2173
2945
  path: "/asset/{assetKey}/unscrap",
2174
2946
  pathParameters: [{
@@ -2177,7 +2949,7 @@ const surfaceCommands = [
2177
2949
  required: true
2178
2950
  }],
2179
2951
  queryFlags: [],
2180
- takesBody: false
2952
+ bodyFlags: []
2181
2953
  })]
2182
2954
  },
2183
2955
  {
@@ -2189,6 +2961,7 @@ const surfaceCommands = [
2189
2961
  subcommands: [defineOperation({
2190
2962
  name: "list",
2191
2963
  summary: "Get asset URL links",
2964
+ example: "hardfin asset url-link list ast_4f9xk2mq7plr8stz",
2192
2965
  method: "GET",
2193
2966
  path: "/asset/{assetKey}/url-link",
2194
2967
  pathParameters: [{
@@ -2197,10 +2970,11 @@ const surfaceCommands = [
2197
2970
  required: true
2198
2971
  }],
2199
2972
  queryFlags: [],
2200
- takesBody: false
2973
+ bodyFlags: []
2201
2974
  }), defineOperation({
2202
2975
  name: "create",
2203
2976
  summary: "Create asset URL link",
2977
+ example: "hardfin asset url-link create ast_4f9xk2mq7plr8stz --url <value>",
2204
2978
  method: "POST",
2205
2979
  path: "/asset/{assetKey}/url-link",
2206
2980
  pathParameters: [{
@@ -2209,7 +2983,21 @@ const surfaceCommands = [
2209
2983
  required: true
2210
2984
  }],
2211
2985
  queryFlags: [],
2212
- takesBody: true
2986
+ bodyFlags: [{
2987
+ name: "name",
2988
+ jsonPath: ["name"],
2989
+ description: "The link's display name, or null to show the address instead",
2990
+ valueName: "value",
2991
+ nullable: true,
2992
+ schema: z.string()
2993
+ }, {
2994
+ name: "url",
2995
+ jsonPath: ["url"],
2996
+ description: "The address the link points to",
2997
+ valueName: "value",
2998
+ required: true,
2999
+ schema: z.string()
3000
+ }]
2213
3001
  })]
2214
3002
  },
2215
3003
  {
@@ -2221,6 +3009,7 @@ const surfaceCommands = [
2221
3009
  subcommands: [defineOperation({
2222
3010
  name: "create",
2223
3011
  summary: "Create asset useful life revision",
3012
+ example: "hardfin asset useful-life-revision create ast_4f9xk2mq7plr8stz --effective-date <value> --reason <value> --useful-life-months <number>",
2224
3013
  method: "POST",
2225
3014
  path: "/asset/{assetKey}/useful-life-revision",
2226
3015
  pathParameters: [{
@@ -2229,7 +3018,48 @@ const surfaceCommands = [
2229
3018
  required: true
2230
3019
  }],
2231
3020
  queryFlags: [],
2232
- takesBody: true
3021
+ bodyFlags: [
3022
+ {
3023
+ name: "effective-date",
3024
+ jsonPath: ["effectiveDate"],
3025
+ description: "The day the revised useful life takes effect, which cannot be in the future",
3026
+ valueName: "value",
3027
+ required: true,
3028
+ schema: z.string()
3029
+ },
3030
+ {
3031
+ name: "notes",
3032
+ jsonPath: ["notes"],
3033
+ description: "Free-form detail about the revision, which a reason of OTHER requires",
3034
+ valueName: "value",
3035
+ nullable: true,
3036
+ schema: z.string()
3037
+ },
3038
+ {
3039
+ name: "reason",
3040
+ jsonPath: ["reason"],
3041
+ description: "Why the useful life was revised",
3042
+ valueName: "value",
3043
+ required: true,
3044
+ schema: z.enum([
3045
+ "CHANGE_IN_USE",
3046
+ "DAMAGE",
3047
+ "OBSOLESCENCE",
3048
+ "OTHER",
3049
+ "REASSESSMENT",
3050
+ "REFURBISHMENT",
3051
+ "REGULATORY"
3052
+ ])
3053
+ },
3054
+ {
3055
+ name: "useful-life-months",
3056
+ jsonPath: ["usefulLifeMonths"],
3057
+ description: "The asset's revised useful life in months",
3058
+ valueName: "number",
3059
+ required: true,
3060
+ schema: z.coerce.number()
3061
+ }
3062
+ ]
2233
3063
  })]
2234
3064
  }
2235
3065
  ]
@@ -2244,6 +3074,7 @@ const surfaceCommands = [
2244
3074
  defineOperation({
2245
3075
  name: "list",
2246
3076
  summary: "Get customers",
3077
+ example: "hardfin customer list --limit 10",
2247
3078
  method: "GET",
2248
3079
  path: "/customer",
2249
3080
  pathParameters: [],
@@ -2315,20 +3146,99 @@ const surfaceCommands = [
2315
3146
  schema: z.string()
2316
3147
  }
2317
3148
  ],
2318
- takesBody: false
3149
+ bodyFlags: []
2319
3150
  }),
2320
3151
  defineOperation({
2321
3152
  name: "create",
2322
3153
  summary: "Create customer",
3154
+ example: "hardfin customer create --name <value>",
2323
3155
  method: "POST",
2324
3156
  path: "/customer",
2325
3157
  pathParameters: [],
2326
3158
  queryFlags: [],
2327
- takesBody: true
3159
+ bodyFlags: [
3160
+ {
3161
+ name: "billing-address",
3162
+ jsonPath: ["billingAddress"],
3163
+ description: "The address invoices are sent to",
3164
+ valueName: "value",
3165
+ nullable: true,
3166
+ schema: z.string()
3167
+ },
3168
+ {
3169
+ name: "billing-contact-email",
3170
+ jsonPath: ["billingContact", "email"],
3171
+ description: "The billing contact's email address",
3172
+ valueName: "value",
3173
+ nullable: true,
3174
+ schema: z.string()
3175
+ },
3176
+ {
3177
+ name: "billing-contact-name",
3178
+ jsonPath: ["billingContact", "name"],
3179
+ description: "The billing contact's name",
3180
+ valueName: "value",
3181
+ nullable: true,
3182
+ schema: z.string()
3183
+ },
3184
+ {
3185
+ name: "billing-contact-phone",
3186
+ jsonPath: ["billingContact", "phone"],
3187
+ description: "The billing contact's phone number",
3188
+ valueName: "value",
3189
+ nullable: true,
3190
+ schema: z.string()
3191
+ },
3192
+ {
3193
+ name: "comment",
3194
+ jsonPath: ["comment"],
3195
+ description: "A free-form note about the customer",
3196
+ valueName: "value",
3197
+ nullable: true,
3198
+ schema: z.string()
3199
+ },
3200
+ {
3201
+ name: "domain",
3202
+ jsonPath: ["domain"],
3203
+ description: "The customer's web domain, used to look up its logo",
3204
+ valueName: "value",
3205
+ nullable: true,
3206
+ schema: z.string()
3207
+ },
3208
+ {
3209
+ name: "external-id",
3210
+ jsonPath: ["externalId"],
3211
+ description: "The customer's identifier in another system",
3212
+ valueName: "value",
3213
+ nullable: true,
3214
+ schema: z.string()
3215
+ },
3216
+ {
3217
+ name: "is-customer",
3218
+ jsonPath: ["isCustomer"],
3219
+ description: "Whether the company is a customer",
3220
+ schema: z.boolean()
3221
+ },
3222
+ {
3223
+ name: "is-supplier",
3224
+ jsonPath: ["isSupplier"],
3225
+ description: "Whether the company is a supplier",
3226
+ schema: z.boolean()
3227
+ },
3228
+ {
3229
+ name: "name",
3230
+ jsonPath: ["name"],
3231
+ description: "The customer's display name",
3232
+ valueName: "value",
3233
+ required: true,
3234
+ schema: z.string()
3235
+ }
3236
+ ]
2328
3237
  }),
2329
3238
  defineOperation({
2330
3239
  name: "get",
2331
3240
  summary: "Get customer",
3241
+ example: "hardfin customer get cust_V1StGXR8Z5jdHi6B",
2332
3242
  method: "GET",
2333
3243
  path: "/customer/{customerKey}",
2334
3244
  pathParameters: [{
@@ -2337,11 +3247,12 @@ const surfaceCommands = [
2337
3247
  required: true
2338
3248
  }],
2339
3249
  queryFlags: [],
2340
- takesBody: false
3250
+ bodyFlags: []
2341
3251
  }),
2342
3252
  defineOperation({
2343
3253
  name: "update",
2344
3254
  summary: "Patch customer",
3255
+ example: "hardfin customer update cust_V1StGXR8Z5jdHi6B",
2345
3256
  method: "PATCH",
2346
3257
  path: "/customer/{customerKey}",
2347
3258
  pathParameters: [{
@@ -2350,7 +3261,93 @@ const surfaceCommands = [
2350
3261
  required: true
2351
3262
  }],
2352
3263
  queryFlags: [],
2353
- takesBody: true
3264
+ bodyFlags: [
3265
+ {
3266
+ name: "billing-address",
3267
+ jsonPath: ["billingAddress"],
3268
+ description: "The address invoices are sent to",
3269
+ valueName: "value",
3270
+ nullable: true,
3271
+ schema: z.string()
3272
+ },
3273
+ {
3274
+ name: "billing-contact-email",
3275
+ jsonPath: ["billingContact", "email"],
3276
+ description: "The billing contact's email address",
3277
+ valueName: "value",
3278
+ nullable: true,
3279
+ schema: z.string()
3280
+ },
3281
+ {
3282
+ name: "billing-contact-name",
3283
+ jsonPath: ["billingContact", "name"],
3284
+ description: "The billing contact's name",
3285
+ valueName: "value",
3286
+ nullable: true,
3287
+ schema: z.string()
3288
+ },
3289
+ {
3290
+ name: "billing-contact-phone",
3291
+ jsonPath: ["billingContact", "phone"],
3292
+ description: "The billing contact's phone number",
3293
+ valueName: "value",
3294
+ nullable: true,
3295
+ schema: z.string()
3296
+ },
3297
+ {
3298
+ name: "comment",
3299
+ jsonPath: ["comment"],
3300
+ description: "A free-form note about the customer",
3301
+ valueName: "value",
3302
+ nullable: true,
3303
+ schema: z.string()
3304
+ },
3305
+ {
3306
+ name: "domain",
3307
+ jsonPath: ["domain"],
3308
+ description: "The customer's web domain, used to look up its logo",
3309
+ valueName: "value",
3310
+ nullable: true,
3311
+ schema: z.string()
3312
+ },
3313
+ {
3314
+ name: "external-id",
3315
+ jsonPath: ["externalId"],
3316
+ description: "The customer's identifier in another system",
3317
+ valueName: "value",
3318
+ nullable: true,
3319
+ schema: z.string()
3320
+ },
3321
+ {
3322
+ name: "is-archived",
3323
+ jsonPath: ["isArchived"],
3324
+ description: "Whether the customer is archived",
3325
+ nullable: true,
3326
+ schema: z.boolean()
3327
+ },
3328
+ {
3329
+ name: "is-customer",
3330
+ jsonPath: ["isCustomer"],
3331
+ description: "Whether the company is a customer",
3332
+ nullable: true,
3333
+ schema: z.boolean()
3334
+ },
3335
+ {
3336
+ name: "is-supplier",
3337
+ jsonPath: ["isSupplier"],
3338
+ description: "Whether the company is a supplier",
3339
+ nullable: true,
3340
+ schema: z.boolean()
3341
+ },
3342
+ {
3343
+ name: "name",
3344
+ jsonPath: ["name"],
3345
+ description: "The customer's display name",
3346
+ valueName: "value",
3347
+ nullable: true,
3348
+ schema: z.string()
3349
+ }
3350
+ ]
2354
3351
  })
2355
3352
  ]
2356
3353
  },
@@ -2363,14 +3360,44 @@ const surfaceCommands = [
2363
3360
  subcommands: [defineOperation({
2364
3361
  name: "create",
2365
3362
  summary: "Upload file",
3363
+ example: "hardfin file create --file-type <value> --for-entity <value> --file photo.jpg",
2366
3364
  method: "POST",
2367
3365
  path: "/file",
2368
3366
  pathParameters: [],
2369
3367
  queryFlags: [],
2370
- takesBody: true
3368
+ bodyFlags: [],
3369
+ upload: {
3370
+ filePart: "data",
3371
+ fields: [
3372
+ {
3373
+ name: "file-type",
3374
+ jsonPath: ["fileType"],
3375
+ description: "The kind of file uploaded, which is ASSET_FILE, the only kind the API uploads",
3376
+ valueName: "value",
3377
+ required: true,
3378
+ schema: z.string()
3379
+ },
3380
+ {
3381
+ name: "for-entity",
3382
+ jsonPath: ["forEntity"],
3383
+ description: "The ID of the asset the file is attached to",
3384
+ valueName: "value",
3385
+ required: true,
3386
+ schema: z.string()
3387
+ },
3388
+ {
3389
+ name: "is-public",
3390
+ jsonPath: ["isPublic"],
3391
+ description: "Whether any organization's API key may download the file, which is false unless sent as true",
3392
+ valueName: "value",
3393
+ schema: z.string()
3394
+ }
3395
+ ]
3396
+ }
2371
3397
  }), defineOperation({
2372
3398
  name: "get",
2373
3399
  summary: "Get file",
3400
+ example: "hardfin file get file_7hq2mx9pkr4stz8w",
2374
3401
  method: "GET",
2375
3402
  path: "/file/{fileKey}",
2376
3403
  pathParameters: [{
@@ -2384,7 +3411,7 @@ const surfaceCommands = [
2384
3411
  description: "True when the file downloads as an attachment rather than opening inline",
2385
3412
  schema: z.boolean()
2386
3413
  }],
2387
- takesBody: false
3414
+ bodyFlags: []
2388
3415
  })]
2389
3416
  },
2390
3417
  {
@@ -2397,6 +3424,7 @@ const surfaceCommands = [
2397
3424
  defineOperation({
2398
3425
  name: "list",
2399
3426
  summary: "Get items",
3427
+ example: "hardfin item list --limit 10",
2400
3428
  method: "GET",
2401
3429
  path: "/item",
2402
3430
  pathParameters: [],
@@ -2471,20 +3499,130 @@ const surfaceCommands = [
2471
3499
  schema: z.string()
2472
3500
  }
2473
3501
  ],
2474
- takesBody: false
3502
+ bodyFlags: []
2475
3503
  }),
2476
3504
  defineOperation({
2477
3505
  name: "create",
2478
3506
  summary: "Create item",
3507
+ example: "hardfin item create --name <value> --sku <value> --type <value>",
2479
3508
  method: "POST",
2480
3509
  path: "/item",
2481
3510
  pathParameters: [],
2482
3511
  queryFlags: [],
2483
- takesBody: true
3512
+ bodyFlags: [
3513
+ {
3514
+ name: "accepts-bulk-serials",
3515
+ jsonPath: ["acceptsBulkSerials"],
3516
+ description: "Whether a BULK item records serial numbers on its units, which SERVICE and DEVICE items ignore",
3517
+ schema: z.boolean()
3518
+ },
3519
+ {
3520
+ name: "description",
3521
+ jsonPath: ["description"],
3522
+ description: "A free-form description of the item",
3523
+ valueName: "value",
3524
+ nullable: true,
3525
+ schema: z.string()
3526
+ },
3527
+ {
3528
+ name: "name",
3529
+ jsonPath: ["name"],
3530
+ description: "The item's display name",
3531
+ valueName: "value",
3532
+ required: true,
3533
+ schema: z.string()
3534
+ },
3535
+ {
3536
+ name: "sku",
3537
+ jsonPath: ["sku"],
3538
+ description: "The item's stock keeping unit, unique within your organization",
3539
+ valueName: "value",
3540
+ required: true,
3541
+ schema: z.string()
3542
+ },
3543
+ {
3544
+ name: "type",
3545
+ jsonPath: ["type"],
3546
+ description: "SERVICE for a non-physical item, DEVICE for a physical item tracked by serial number, or BULK for a part tracked by quantity",
3547
+ valueName: "value",
3548
+ required: true,
3549
+ schema: z.enum([
3550
+ "BULK",
3551
+ "DEVICE",
3552
+ "SERVICE"
3553
+ ])
3554
+ },
3555
+ {
3556
+ name: "unit-of-measure",
3557
+ jsonPath: ["unitOfMeasure"],
3558
+ description: "The unit a BULK item's quantities are counted in, which SERVICE and DEVICE items ignore",
3559
+ valueName: "value",
3560
+ schema: z.enum([
3561
+ "BG",
3562
+ "BO",
3563
+ "BX",
3564
+ "C62",
3565
+ "CMK",
3566
+ "CMT",
3567
+ "CR",
3568
+ "CS",
3569
+ "CT",
3570
+ "DMQ",
3571
+ "DR",
3572
+ "DZN",
3573
+ "EA",
3574
+ "EN",
3575
+ "FOT",
3576
+ "FTK",
3577
+ "FTQ",
3578
+ "GLL",
3579
+ "GRM",
3580
+ "GRO",
3581
+ "H87",
3582
+ "INH",
3583
+ "INK",
3584
+ "INQ",
3585
+ "KG",
3586
+ "KGM",
3587
+ "KMT",
3588
+ "KT",
3589
+ "LBR",
3590
+ "LO",
3591
+ "LTR",
3592
+ "MGM",
3593
+ "MLT",
3594
+ "MMK",
3595
+ "MMT",
3596
+ "MTK",
3597
+ "MTQ",
3598
+ "MTR",
3599
+ "ONZ",
3600
+ "OZA",
3601
+ "PK",
3602
+ "PR",
3603
+ "PTI",
3604
+ "PX",
3605
+ "QTI",
3606
+ "RL",
3607
+ "RO",
3608
+ "SET",
3609
+ "SMI",
3610
+ "ST",
3611
+ "STN",
3612
+ "SV",
3613
+ "TNE",
3614
+ "TU",
3615
+ "YDK",
3616
+ "YDQ",
3617
+ "YRD"
3618
+ ])
3619
+ }
3620
+ ]
2484
3621
  }),
2485
3622
  defineOperation({
2486
3623
  name: "get",
2487
3624
  summary: "Get item",
3625
+ example: "hardfin item get item_7Hq2Lm9XcR4tWz8K",
2488
3626
  method: "GET",
2489
3627
  path: "/item/{itemKey}",
2490
3628
  pathParameters: [{
@@ -2493,11 +3631,12 @@ const surfaceCommands = [
2493
3631
  required: true
2494
3632
  }],
2495
3633
  queryFlags: [],
2496
- takesBody: false
3634
+ bodyFlags: []
2497
3635
  }),
2498
3636
  defineOperation({
2499
3637
  name: "update",
2500
3638
  summary: "Update item",
3639
+ example: "hardfin item update item_7Hq2Lm9XcR4tWz8K",
2501
3640
  method: "PATCH",
2502
3641
  path: "/item/{itemKey}",
2503
3642
  pathParameters: [{
@@ -2506,7 +3645,71 @@ const surfaceCommands = [
2506
3645
  required: true
2507
3646
  }],
2508
3647
  queryFlags: [],
2509
- takesBody: true
3648
+ bodyFlags: [
3649
+ {
3650
+ name: "accepts-bulk-serials",
3651
+ jsonPath: ["acceptsBulkSerials"],
3652
+ description: "Whether a BULK item records serial numbers on its units, read only beside type",
3653
+ nullable: true,
3654
+ schema: z.boolean()
3655
+ },
3656
+ {
3657
+ name: "description",
3658
+ jsonPath: ["description"],
3659
+ description: "The item's new description, or null to clear it",
3660
+ valueName: "value",
3661
+ nullable: true,
3662
+ schema: z.string()
3663
+ },
3664
+ {
3665
+ name: "field",
3666
+ jsonPath: ["fields"],
3667
+ description: "New positions for a DEVICE item's fields",
3668
+ valueName: "fieldId=,order=",
3669
+ repeatable: true,
3670
+ element: [
3671
+ "fieldId",
3672
+ "order",
3673
+ "section"
3674
+ ],
3675
+ schema: z.array(z.string())
3676
+ },
3677
+ {
3678
+ name: "is-archived",
3679
+ jsonPath: ["isArchived"],
3680
+ description: "Whether the item is archived, which cannot be null",
3681
+ nullable: true,
3682
+ schema: z.boolean()
3683
+ },
3684
+ {
3685
+ name: "name",
3686
+ jsonPath: ["name"],
3687
+ description: "The item's new display name, which cannot be empty",
3688
+ valueName: "value",
3689
+ nullable: true,
3690
+ schema: z.string()
3691
+ },
3692
+ {
3693
+ name: "sku",
3694
+ jsonPath: ["sku"],
3695
+ description: "The item's new stock keeping unit, which cannot be empty and must be unique within your organization",
3696
+ valueName: "value",
3697
+ nullable: true,
3698
+ schema: z.string()
3699
+ },
3700
+ {
3701
+ name: "type",
3702
+ jsonPath: ["type"],
3703
+ description: "The type to convert the item to, when the item's assets and inventory history allow the conversion",
3704
+ valueName: "value",
3705
+ nullable: true,
3706
+ schema: z.enum([
3707
+ "BULK",
3708
+ "DEVICE",
3709
+ "SERVICE"
3710
+ ])
3711
+ }
3712
+ ]
2510
3713
  }),
2511
3714
  {
2512
3715
  name: "accounting",
@@ -2517,6 +3720,7 @@ const surfaceCommands = [
2517
3720
  subcommands: [defineOperation({
2518
3721
  name: "update",
2519
3722
  summary: "Update item accounting",
3723
+ example: "hardfin item accounting update item_7Hq2Lm9XcR4tWz8K",
2520
3724
  method: "PATCH",
2521
3725
  path: "/item/{itemKey}/accounting",
2522
3726
  pathParameters: [{
@@ -2525,7 +3729,116 @@ const surfaceCommands = [
2525
3729
  required: true
2526
3730
  }],
2527
3731
  queryFlags: [],
2528
- takesBody: true
3732
+ bodyFlags: [
3733
+ {
3734
+ name: "allocated-indirect",
3735
+ jsonPath: ["allocatedIndirect"],
3736
+ description: "One unit's share of overhead, a cost component",
3737
+ valueName: "value",
3738
+ nullable: true,
3739
+ schema: z.string()
3740
+ },
3741
+ {
3742
+ name: "bill-of-materials",
3743
+ jsonPath: ["billOfMaterials"],
3744
+ description: "The parts cost of one unit, a cost component",
3745
+ valueName: "value",
3746
+ nullable: true,
3747
+ schema: z.string()
3748
+ },
3749
+ {
3750
+ name: "depreciation-model",
3751
+ jsonPath: ["depreciationModel"],
3752
+ description: "The method one unit is depreciated by, or null to clear it",
3753
+ valueName: "value",
3754
+ schema: z.enum([
3755
+ "DOUBLE_DECLINING",
3756
+ "STRAIGHT_LINE",
3757
+ "SUM_YEAR",
3758
+ "UNIT_OF_PRODUCTION"
3759
+ ])
3760
+ },
3761
+ {
3762
+ name: "direct-labor",
3763
+ jsonPath: ["directLabor"],
3764
+ description: "The labor cost to build one unit, a cost component",
3765
+ valueName: "value",
3766
+ nullable: true,
3767
+ schema: z.string()
3768
+ },
3769
+ {
3770
+ name: "freight-inbound",
3771
+ jsonPath: ["freightInbound"],
3772
+ description: "The shipping cost to receive one unit, a cost component",
3773
+ valueName: "value",
3774
+ nullable: true,
3775
+ schema: z.string()
3776
+ },
3777
+ {
3778
+ name: "freight-outbound",
3779
+ jsonPath: ["freightOutbound"],
3780
+ description: "The shipping cost to deploy one unit, a deployment cost component",
3781
+ valueName: "value",
3782
+ nullable: true,
3783
+ schema: z.string()
3784
+ },
3785
+ {
3786
+ name: "installation",
3787
+ jsonPath: ["installation"],
3788
+ description: "The cost to install one unit, a deployment cost component",
3789
+ valueName: "value",
3790
+ nullable: true,
3791
+ schema: z.string()
3792
+ },
3793
+ {
3794
+ name: "interest",
3795
+ jsonPath: ["interest"],
3796
+ description: "The financing cost of one unit, a cost component",
3797
+ valueName: "value",
3798
+ nullable: true,
3799
+ schema: z.string()
3800
+ },
3801
+ {
3802
+ name: "salvage-value",
3803
+ jsonPath: ["salvageValue"],
3804
+ description: "The value one unit keeps at the end of its useful life, or null to clear it",
3805
+ valueName: "value",
3806
+ nullable: true,
3807
+ schema: z.string()
3808
+ },
3809
+ {
3810
+ name: "simple-cost-basis",
3811
+ jsonPath: ["simpleCostBasis"],
3812
+ description: "A single cost for one unit, which cannot be sent together with the cost components",
3813
+ valueName: "value",
3814
+ nullable: true,
3815
+ schema: z.string()
3816
+ },
3817
+ {
3818
+ name: "tariffs",
3819
+ jsonPath: ["tariffs"],
3820
+ description: "The import duty paid on one unit, a cost component",
3821
+ valueName: "value",
3822
+ nullable: true,
3823
+ schema: z.string()
3824
+ },
3825
+ {
3826
+ name: "tax",
3827
+ jsonPath: ["tax"],
3828
+ description: "The tax paid on one unit, a cost component",
3829
+ valueName: "value",
3830
+ nullable: true,
3831
+ schema: z.string()
3832
+ },
3833
+ {
3834
+ name: "useful-life",
3835
+ jsonPath: ["usefulLife"],
3836
+ description: "The number of months one unit is depreciated over, or null to clear it",
3837
+ valueName: "number",
3838
+ nullable: true,
3839
+ schema: z.coerce.number()
3840
+ }
3841
+ ]
2529
3842
  })]
2530
3843
  },
2531
3844
  {
@@ -2538,6 +3851,7 @@ const surfaceCommands = [
2538
3851
  defineOperation({
2539
3852
  name: "create",
2540
3853
  summary: "Create item field",
3854
+ example: "hardfin item field create item_7Hq2Lm9XcR4tWz8K --field-type <value> --label <value> --order <number>",
2541
3855
  method: "POST",
2542
3856
  path: "/item/{itemKey}/field",
2543
3857
  pathParameters: [{
@@ -2546,11 +3860,56 @@ const surfaceCommands = [
2546
3860
  required: true
2547
3861
  }],
2548
3862
  queryFlags: [],
2549
- takesBody: true
3863
+ bodyFlags: [
3864
+ {
3865
+ name: "field-type",
3866
+ jsonPath: ["fieldType"],
3867
+ description: "The kind of value the field holds",
3868
+ valueName: "value",
3869
+ required: true,
3870
+ schema: z.enum([
3871
+ "BOOLEAN",
3872
+ "DATE",
3873
+ "DATE_TIME",
3874
+ "INTEGER",
3875
+ "MULTILINE_TEXT",
3876
+ "NUMBER",
3877
+ "TEXT",
3878
+ "TIME"
3879
+ ])
3880
+ },
3881
+ {
3882
+ name: "label",
3883
+ jsonPath: ["label"],
3884
+ description: "The field's display name",
3885
+ valueName: "value",
3886
+ required: true,
3887
+ schema: z.string()
3888
+ },
3889
+ {
3890
+ name: "order",
3891
+ jsonPath: ["order"],
3892
+ description: "The field's position within its section, starting at 0",
3893
+ valueName: "number",
3894
+ required: true,
3895
+ nullable: true,
3896
+ schema: z.coerce.number()
3897
+ },
3898
+ {
3899
+ name: "section",
3900
+ jsonPath: ["section"],
3901
+ description: "The group the field is shown in, starting at 0",
3902
+ valueName: "number",
3903
+ required: true,
3904
+ nullable: true,
3905
+ schema: z.coerce.number()
3906
+ }
3907
+ ]
2550
3908
  }),
2551
3909
  defineOperation({
2552
3910
  name: "update",
2553
3911
  summary: "Update item field",
3912
+ example: "hardfin item field update item_7Hq2Lm9XcR4tWz8K pfield_2wn8kq4lxp7rtz3m",
2554
3913
  method: "PATCH",
2555
3914
  path: "/item/{itemKey}/field/{fieldKey}",
2556
3915
  pathParameters: [{
@@ -2563,11 +3922,19 @@ const surfaceCommands = [
2563
3922
  required: true
2564
3923
  }],
2565
3924
  queryFlags: [],
2566
- takesBody: true
3925
+ bodyFlags: [{
3926
+ name: "label",
3927
+ jsonPath: ["label"],
3928
+ description: "The field's new display name, which cannot be empty",
3929
+ valueName: "value",
3930
+ nullable: true,
3931
+ schema: z.string()
3932
+ }]
2567
3933
  }),
2568
3934
  defineOperation({
2569
3935
  name: "delete",
2570
3936
  summary: "Delete item field",
3937
+ example: "hardfin item field delete item_7Hq2Lm9XcR4tWz8K pfield_2wn8kq4lxp7rtz3m",
2571
3938
  method: "DELETE",
2572
3939
  path: "/item/{itemKey}/field/{fieldKey}",
2573
3940
  pathParameters: [{
@@ -2580,7 +3947,7 @@ const surfaceCommands = [
2580
3947
  required: true
2581
3948
  }],
2582
3949
  queryFlags: [],
2583
- takesBody: false
3950
+ bodyFlags: []
2584
3951
  })
2585
3952
  ]
2586
3953
  }
@@ -2596,6 +3963,7 @@ const surfaceCommands = [
2596
3963
  defineOperation({
2597
3964
  name: "list",
2598
3965
  summary: "Get location listing",
3966
+ example: "hardfin location list --limit 10",
2599
3967
  method: "GET",
2600
3968
  path: "/location",
2601
3969
  pathParameters: [],
@@ -2684,20 +4052,147 @@ const surfaceCommands = [
2684
4052
  schema: z.array(z.string())
2685
4053
  }
2686
4054
  ],
2687
- takesBody: false
4055
+ bodyFlags: []
2688
4056
  }),
2689
4057
  defineOperation({
2690
4058
  name: "create",
2691
4059
  summary: "Create location",
4060
+ example: "hardfin location create",
2692
4061
  method: "POST",
2693
4062
  path: "/location",
2694
4063
  pathParameters: [],
2695
4064
  queryFlags: [],
2696
- takesBody: true
4065
+ bodyFlags: [
4066
+ {
4067
+ name: "address-line1",
4068
+ jsonPath: ["address", "addressLine1"],
4069
+ description: "The first line of the street address",
4070
+ valueName: "value",
4071
+ nullable: true,
4072
+ schema: z.string()
4073
+ },
4074
+ {
4075
+ name: "address-line2",
4076
+ jsonPath: ["address", "addressLine2"],
4077
+ description: "The second line of the street address, such as a suite",
4078
+ valueName: "value",
4079
+ nullable: true,
4080
+ schema: z.string()
4081
+ },
4082
+ {
4083
+ name: "address-city",
4084
+ jsonPath: ["address", "city"],
4085
+ description: "The city",
4086
+ valueName: "value",
4087
+ nullable: true,
4088
+ schema: z.string()
4089
+ },
4090
+ {
4091
+ name: "address-country",
4092
+ jsonPath: ["address", "country"],
4093
+ description: "The country",
4094
+ valueName: "value",
4095
+ nullable: true,
4096
+ schema: z.string()
4097
+ },
4098
+ {
4099
+ name: "address-formatted-address",
4100
+ jsonPath: ["address", "formattedAddress"],
4101
+ description: "The whole address on one line",
4102
+ valueName: "value",
4103
+ nullable: true,
4104
+ schema: z.string()
4105
+ },
4106
+ {
4107
+ name: "address-postal-code",
4108
+ jsonPath: ["address", "postalCode"],
4109
+ description: "The postal or ZIP code",
4110
+ valueName: "value",
4111
+ nullable: true,
4112
+ schema: z.string()
4113
+ },
4114
+ {
4115
+ name: "address-state",
4116
+ jsonPath: ["address", "state"],
4117
+ description: "The state or region",
4118
+ valueName: "value",
4119
+ nullable: true,
4120
+ schema: z.string()
4121
+ },
4122
+ {
4123
+ name: "consignee",
4124
+ jsonPath: ["consignee"],
4125
+ description: "The ID of the customer a zone is designated for, such as for reservations, provisioning or a 3PL",
4126
+ valueName: "value",
4127
+ nullable: true,
4128
+ schema: z.string()
4129
+ },
4130
+ {
4131
+ name: "customer-id",
4132
+ jsonPath: ["customerId"],
4133
+ description: "The ID of the customer to assign a site to, or null for your organization's own site",
4134
+ valueName: "value",
4135
+ nullable: true,
4136
+ schema: z.string()
4137
+ },
4138
+ {
4139
+ name: "description",
4140
+ jsonPath: ["description"],
4141
+ description: "A free-form description of a zone",
4142
+ valueName: "value",
4143
+ nullable: true,
4144
+ schema: z.string()
4145
+ },
4146
+ {
4147
+ name: "is-inventory",
4148
+ jsonPath: ["isInventory"],
4149
+ description: "Whether assets at the location count as inventory for reporting",
4150
+ schema: z.boolean()
4151
+ },
4152
+ {
4153
+ name: "is-inventory-override",
4154
+ jsonPath: ["isInventoryOverride"],
4155
+ description: "Whether a zone sets its own isInventory rather than inheriting its parent site's, which a site refuses",
4156
+ schema: z.boolean()
4157
+ },
4158
+ {
4159
+ name: "is-transient",
4160
+ jsonPath: ["isTransient"],
4161
+ description: "Whether assets make only occasional or temporary stops at the location, which hides it from location lists by default",
4162
+ schema: z.boolean()
4163
+ },
4164
+ {
4165
+ name: "name",
4166
+ jsonPath: ["name"],
4167
+ description: "The location's display name",
4168
+ valueName: "value",
4169
+ schema: z.string()
4170
+ },
4171
+ {
4172
+ name: "parent-location-id",
4173
+ jsonPath: ["parentLocationId"],
4174
+ description: "The ID of the site a zone belongs to, required for a zone and refused for a site",
4175
+ valueName: "value",
4176
+ nullable: true,
4177
+ schema: z.string()
4178
+ },
4179
+ {
4180
+ name: "type",
4181
+ jsonPath: ["type"],
4182
+ description: "SITE for a site, or ZONE for a zone within a site",
4183
+ valueName: "value",
4184
+ schema: z.enum([
4185
+ "SITE",
4186
+ "UNKNOWN",
4187
+ "ZONE"
4188
+ ])
4189
+ }
4190
+ ]
2697
4191
  }),
2698
4192
  defineOperation({
2699
4193
  name: "get",
2700
4194
  summary: "Get location",
4195
+ example: "hardfin location get loc_4f9Xk2mQ7pLr8sTz",
2701
4196
  method: "GET",
2702
4197
  path: "/location/{locationKey}",
2703
4198
  pathParameters: [{
@@ -2706,11 +4201,12 @@ const surfaceCommands = [
2706
4201
  required: true
2707
4202
  }],
2708
4203
  queryFlags: [],
2709
- takesBody: false
4204
+ bodyFlags: []
2710
4205
  }),
2711
4206
  defineOperation({
2712
4207
  name: "update",
2713
4208
  summary: "Patch location",
4209
+ example: "hardfin location update loc_4f9Xk2mQ7pLr8sTz",
2714
4210
  method: "PATCH",
2715
4211
  path: "/location/{locationKey}",
2716
4212
  pathParameters: [{
@@ -2719,7 +4215,135 @@ const surfaceCommands = [
2719
4215
  required: true
2720
4216
  }],
2721
4217
  queryFlags: [],
2722
- takesBody: true
4218
+ bodyFlags: [
4219
+ {
4220
+ name: "address-line1",
4221
+ jsonPath: ["address", "addressLine1"],
4222
+ description: "The first line of the street address",
4223
+ valueName: "value",
4224
+ nullable: true,
4225
+ schema: z.string()
4226
+ },
4227
+ {
4228
+ name: "address-line2",
4229
+ jsonPath: ["address", "addressLine2"],
4230
+ description: "The second line of the street address, such as a suite",
4231
+ valueName: "value",
4232
+ nullable: true,
4233
+ schema: z.string()
4234
+ },
4235
+ {
4236
+ name: "address-city",
4237
+ jsonPath: ["address", "city"],
4238
+ description: "The city",
4239
+ valueName: "value",
4240
+ nullable: true,
4241
+ schema: z.string()
4242
+ },
4243
+ {
4244
+ name: "address-country",
4245
+ jsonPath: ["address", "country"],
4246
+ description: "The country",
4247
+ valueName: "value",
4248
+ nullable: true,
4249
+ schema: z.string()
4250
+ },
4251
+ {
4252
+ name: "address-formatted-address",
4253
+ jsonPath: ["address", "formattedAddress"],
4254
+ description: "The whole address on one line",
4255
+ valueName: "value",
4256
+ nullable: true,
4257
+ schema: z.string()
4258
+ },
4259
+ {
4260
+ name: "address-postal-code",
4261
+ jsonPath: ["address", "postalCode"],
4262
+ description: "The postal or ZIP code",
4263
+ valueName: "value",
4264
+ nullable: true,
4265
+ schema: z.string()
4266
+ },
4267
+ {
4268
+ name: "address-state",
4269
+ jsonPath: ["address", "state"],
4270
+ description: "The state or region",
4271
+ valueName: "value",
4272
+ nullable: true,
4273
+ schema: z.string()
4274
+ },
4275
+ {
4276
+ name: "consignee",
4277
+ jsonPath: ["consignee"],
4278
+ description: "The ID of the customer a zone is designated for, such as for reservations, provisioning or a 3PL",
4279
+ valueName: "value",
4280
+ nullable: true,
4281
+ schema: z.string()
4282
+ },
4283
+ {
4284
+ name: "customer-id",
4285
+ jsonPath: ["customerId"],
4286
+ description: "The ID of the customer to assign a site to, or null for your organization's own site",
4287
+ valueName: "value",
4288
+ nullable: true,
4289
+ schema: z.string()
4290
+ },
4291
+ {
4292
+ name: "description",
4293
+ jsonPath: ["description"],
4294
+ description: "A free-form description of a zone",
4295
+ valueName: "value",
4296
+ nullable: true,
4297
+ schema: z.string()
4298
+ },
4299
+ {
4300
+ name: "is-archived",
4301
+ jsonPath: ["isArchived"],
4302
+ description: "Whether the location is archived, and archiving a site archives its zones",
4303
+ nullable: true,
4304
+ schema: z.boolean()
4305
+ },
4306
+ {
4307
+ name: "is-inventory",
4308
+ jsonPath: ["isInventory"],
4309
+ description: "Whether assets at the location count as inventory for reporting",
4310
+ nullable: true,
4311
+ schema: z.boolean()
4312
+ },
4313
+ {
4314
+ name: "is-inventory-override",
4315
+ jsonPath: ["isInventoryOverride"],
4316
+ description: "Whether a zone sets its own isInventory rather than inheriting its parent site's, which a site refuses",
4317
+ nullable: true,
4318
+ schema: z.boolean()
4319
+ },
4320
+ {
4321
+ name: "is-transient",
4322
+ jsonPath: ["isTransient"],
4323
+ description: "Whether assets make only occasional or temporary stops at the location, which hides it from location lists by default",
4324
+ nullable: true,
4325
+ schema: z.boolean()
4326
+ },
4327
+ {
4328
+ name: "name",
4329
+ jsonPath: ["name"],
4330
+ description: "The location's display name",
4331
+ valueName: "value",
4332
+ nullable: true,
4333
+ schema: z.string()
4334
+ },
4335
+ {
4336
+ name: "type",
4337
+ jsonPath: ["type"],
4338
+ description: "SITE for a site, or ZONE for a zone within a site",
4339
+ valueName: "value",
4340
+ schema: z.enum([
4341
+ "SITE",
4342
+ "UNKNOWN",
4343
+ "ZONE"
4344
+ ])
4345
+ }
4346
+ ]
2723
4347
  }),
2724
4348
  {
2725
4349
  name: "zones",
@@ -2730,6 +4354,7 @@ const surfaceCommands = [
2730
4354
  subcommands: [defineOperation({
2731
4355
  name: "list",
2732
4356
  summary: "Get zones",
4357
+ example: "hardfin location zones list loc_4f9Xk2mQ7pLr8sTz",
2733
4358
  method: "GET",
2734
4359
  path: "/location/{locationKey}/zones",
2735
4360
  pathParameters: [{
@@ -2748,7 +4373,7 @@ const surfaceCommands = [
2748
4373
  "true"
2749
4374
  ])
2750
4375
  }],
2751
- takesBody: false
4376
+ bodyFlags: []
2752
4377
  })]
2753
4378
  }
2754
4379
  ]
@@ -2763,6 +4388,7 @@ const surfaceCommands = [
2763
4388
  defineOperation({
2764
4389
  name: "get",
2765
4390
  summary: "Get URL link by key",
4391
+ example: "hardfin url-link get link_7hq2mx9pcr4stz8w",
2766
4392
  method: "GET",
2767
4393
  path: "/url-link/{linkKey}",
2768
4394
  pathParameters: [{
@@ -2771,11 +4397,12 @@ const surfaceCommands = [
2771
4397
  required: true
2772
4398
  }],
2773
4399
  queryFlags: [],
2774
- takesBody: false
4400
+ bodyFlags: []
2775
4401
  }),
2776
4402
  defineOperation({
2777
4403
  name: "update",
2778
4404
  summary: "Update URL link",
4405
+ example: "hardfin url-link update link_7hq2mx9pcr4stz8w",
2779
4406
  method: "PATCH",
2780
4407
  path: "/url-link/{linkKey}",
2781
4408
  pathParameters: [{
@@ -2784,11 +4411,26 @@ const surfaceCommands = [
2784
4411
  required: true
2785
4412
  }],
2786
4413
  queryFlags: [],
2787
- takesBody: true
4414
+ bodyFlags: [{
4415
+ name: "name",
4416
+ jsonPath: ["name"],
4417
+ description: "The link's display name, or null to show the address instead",
4418
+ valueName: "value",
4419
+ nullable: true,
4420
+ schema: z.string()
4421
+ }, {
4422
+ name: "url",
4423
+ jsonPath: ["url"],
4424
+ description: "The address the link points to, which cannot be empty or null",
4425
+ valueName: "value",
4426
+ nullable: true,
4427
+ schema: z.string()
4428
+ }]
2788
4429
  }),
2789
4430
  defineOperation({
2790
4431
  name: "delete",
2791
4432
  summary: "Delete URL link",
4433
+ example: "hardfin url-link delete link_7hq2mx9pcr4stz8w",
2792
4434
  method: "DELETE",
2793
4435
  path: "/url-link/{linkKey}",
2794
4436
  pathParameters: [{
@@ -2797,7 +4439,7 @@ const surfaceCommands = [
2797
4439
  required: true
2798
4440
  }],
2799
4441
  queryFlags: [],
2800
- takesBody: false
4442
+ bodyFlags: []
2801
4443
  })
2802
4444
  ]
2803
4445
  }
@@ -3084,7 +4726,9 @@ const commands = [
3084
4726
  apiCommand,
3085
4727
  configCommand,
3086
4728
  agentGuideCommand,
3087
- mcpCommand
4729
+ completionCommand,
4730
+ mcpCommand,
4731
+ completeCommand
3088
4732
  ];
3089
4733
  //#endregion
3090
4734
  //#region src/command/validate.ts
@@ -3100,7 +4744,7 @@ function toRejectedFlag(command, flags) {
3100
4744
  //#region src/cli.ts
3101
4745
  const program = new Command();
3102
4746
  program.name("hardfin").description("Call the Hardfin API from a terminal or an agent").version(version$1, "-v, --version").option("--api-url <url>", "The API to call, whose host also holds the authorization server").option("--issuer-url <url>", "The authorization server, when it does not sit at the API's host").showHelpAfterError().enablePositionalOptions();
3103
- for (const command of commands) program.addCommand(toProgram(command));
4747
+ for (const command of commands) program.addCommand(toProgram(command), { hidden: command.hidden });
3104
4748
  await program.parseAsync(process.argv);
3105
4749
  /** toProgram wires one registry command into the parser. */
3106
4750
  function toProgram(command) {
@@ -3118,7 +4762,7 @@ function toProgram(command) {
3118
4762
  program.addOption(option);
3119
4763
  }
3120
4764
  for (const example of command.examples) program.addHelpText("after", `\n${example.description}:\n $ ${example.command}`);
3121
- for (const subcommand of command.subcommands ?? []) program.addCommand(toProgram(subcommand));
4765
+ for (const subcommand of command.subcommands ?? []) program.addCommand(toProgram(subcommand), { hidden: subcommand.hidden });
3122
4766
  if (!command.run) return program;
3123
4767
  program.action(async (...parsed) => {
3124
4768
  const flags = parsed[parsed.length - 2] ?? {};