@lotics/cli 0.47.0 → 0.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -102,7 +102,10 @@ lotics tools query_records # show full description + input schema
102
102
  lotics run query_tables '{}'
103
103
  lotics run query_records '{"table_id":"tbl_...","field_keys":["name"]}'
104
104
 
105
- # Pipe args via stdin
105
+ # Large args (a knowledge-doc `content`, a bulk update) exceed the OS arg limit —
106
+ # read them from a file or stdin instead of an inline arg:
107
+ lotics run create_knowledge @args.json
108
+ cat args.json | lotics run create_knowledge
106
109
  echo '{"table_id":"tbl_..."}' | lotics run query_records
107
110
 
108
111
  # Upload files (multiple files and directories supported)
package/dist/cli.js CHANGED
@@ -54,6 +54,8 @@ COMMANDS
54
54
  lotics tools List all available tools
55
55
  lotics tools <name> Show tool description and input schema
56
56
  lotics run <tool> '<json>' Execute a tool
57
+ lotics run <tool> @args.json Read JSON args from a file (large payloads)
58
+ cat args.json | lotics run <tool> Read JSON args from stdin (large payloads)
57
59
  lotics upload <file|dir...> Upload files (directories expand to their immediate files)
58
60
  lotics download <file_id> Download a file by ID
59
61
  lotics download record <record_id> <field_key>
@@ -533,7 +535,9 @@ async function main() {
533
535
  process.exit(1);
534
536
  }
535
537
  if (command === "run" && !subcommand) {
536
- console.error('Usage: lotics run <tool> \'<json_args>\'');
538
+ console.error("Usage: lotics run <tool> '<json_args>'\n" +
539
+ " lotics run <tool> @args.json (read args from a file — for large payloads)\n" +
540
+ " cat args.json | lotics run <tool> (read args from stdin)");
537
541
  console.error('Run "lotics tools" to see available tools.');
538
542
  process.exit(1);
539
543
  }
@@ -779,7 +783,23 @@ async function main() {
779
783
  if (command === "run") {
780
784
  const toolName = subcommand;
781
785
  let rawArgs = toolArgs;
782
- if (!rawArgs && !process.stdin.isTTY) {
786
+ if (rawArgs && rawArgs.startsWith("@")) {
787
+ // `@<path>` — read the JSON args from a local file. JSON args always
788
+ // start with `{`, so a leading `@` is unambiguous. This (and piped
789
+ // stdin below) carries payloads too large for an inline arg, which the
790
+ // OS caps (ARG_MAX) — e.g. a knowledge doc's `content` or a bulk update.
791
+ // Reads only a file the caller explicitly named; no new trust boundary.
792
+ const argsPath = rawArgs.slice(1);
793
+ try {
794
+ rawArgs = fs.readFileSync(argsPath, "utf-8");
795
+ }
796
+ catch (err) {
797
+ console.error(`Cannot read args file "${argsPath}": ${err instanceof Error ? err.message : String(err)}`);
798
+ process.exit(1);
799
+ }
800
+ }
801
+ else if (!rawArgs && !process.stdin.isTTY) {
802
+ // Piped/redirected stdin — `… | lotics run <tool>` or `< file.json`.
783
803
  rawArgs = await readStdin();
784
804
  }
785
805
  let args = {};
package/dist/client.d.ts CHANGED
@@ -183,6 +183,21 @@ export declare class LoticsClient {
183
183
  image: string | null;
184
184
  }>;
185
185
  }>;
186
+ /**
187
+ * Resolve the full option set (key, label, color) of a named query's select
188
+ * columns — the picker companion to `appQuery`. Mirrors
189
+ * POST /v1/apps/{app_id}/field-options.
190
+ */
191
+ appFieldOptions(app_id: string, alias: string): Promise<{
192
+ fields: Record<string, {
193
+ label: string;
194
+ options: Array<{
195
+ key: string;
196
+ label: string;
197
+ color: string;
198
+ }>;
199
+ }>;
200
+ }>;
186
201
  /**
187
202
  * Execute a workflow by alias declared in package.json#lotics.workflows.
188
203
  * Mirrors POST /v1/apps/{app_id}/workflows/{alias}/execute.
package/dist/client.js CHANGED
@@ -187,6 +187,14 @@ export class LoticsClient {
187
187
  const qs = group_id ? `?group_id=${encodeURIComponent(group_id)}` : "";
188
188
  return this.request("GET", `/v1/apps/${encodeURIComponent(app_id)}/members${qs}`);
189
189
  }
190
+ /**
191
+ * Resolve the full option set (key, label, color) of a named query's select
192
+ * columns — the picker companion to `appQuery`. Mirrors
193
+ * POST /v1/apps/{app_id}/field-options.
194
+ */
195
+ async appFieldOptions(app_id, alias) {
196
+ return this.request("POST", `/v1/apps/${encodeURIComponent(app_id)}/field-options`, { alias });
197
+ }
190
198
  /**
191
199
  * Execute a workflow by alias declared in package.json#lotics.workflows.
192
200
  * Mirrors POST /v1/apps/{app_id}/workflows/{alias}/execute.
@@ -6,7 +6,7 @@
6
6
  * { message }. Same shape as the production iframe-host's error path.
7
7
  */
8
8
  import { LoticsClient } from "../client.js";
9
- export type RpcOp = "query" | "workflow" | "members" | "context" | "upload_url" | "upload_complete" | "comments.list" | "comments.create" | "comments.update" | "comments.delete" | "comments.counts";
9
+ export type RpcOp = "query" | "field_options" | "workflow" | "members" | "context" | "upload_url" | "upload_complete" | "comments.list" | "comments.create" | "comments.update" | "comments.delete" | "comments.counts";
10
10
  export interface RpcRequest {
11
11
  app_id: string;
12
12
  op: RpcOp;
@@ -7,6 +7,7 @@
7
7
  */
8
8
  const SUPPORTED_OPS = new Set([
9
9
  "query",
10
+ "field_options",
10
11
  "workflow",
11
12
  "members",
12
13
  "context",
@@ -52,6 +53,13 @@ export async function dispatchRpc(client, body, opts) {
52
53
  count: p.count,
53
54
  });
54
55
  }
56
+ case "field_options": {
57
+ const p = body.payload;
58
+ if (!p || typeof p.alias !== "string") {
59
+ throw new Error("field_options payload must include `alias`");
60
+ }
61
+ return client.appFieldOptions(body.app_id, p.alias);
62
+ }
55
63
  case "workflow": {
56
64
  const p = body.payload;
57
65
  if (!p || typeof p.alias !== "string") {
@@ -27,6 +27,27 @@ describe("dispatchRpc — context op", () => {
27
27
  await expect(dispatchRpc(client, { app_id: "app_x", op: "bogus", payload: {} })).rejects.toThrow(/Unknown RPC op/);
28
28
  });
29
29
  });
30
+ describe("dispatchRpc — field_options op", () => {
31
+ it("forwards the alias to appFieldOptions and returns its { fields } shape", async () => {
32
+ const fields = {
33
+ status: {
34
+ label: "Status",
35
+ options: [{ key: "opt_open", label: "Open", color: "blue" }],
36
+ },
37
+ };
38
+ const client = mockClient({ appFieldOptions: async () => ({ fields }) });
39
+ const result = await dispatchRpc(client, {
40
+ app_id: "app_x",
41
+ op: "field_options",
42
+ payload: { alias: "records" },
43
+ });
44
+ expect(result).toEqual({ fields });
45
+ });
46
+ it("requires an alias in the payload", async () => {
47
+ const client = mockClient({ appFieldOptions: async () => ({ fields: {} }) });
48
+ await expect(dispatchRpc(client, { app_id: "app_x", op: "field_options", payload: {} })).rejects.toThrow(/alias/);
49
+ });
50
+ });
30
51
  describe("dispatchRpc — comment ops", () => {
31
52
  it("comments.list forwards to appGetRecordComments, wrapped as { comments }", async () => {
32
53
  const comments = [{ id: "cmt_1", content: "hi" }];
package/dist/src/cli.js CHANGED
@@ -29772,6 +29772,14 @@ var LoticsClient = class {
29772
29772
  const qs = group_id ? `?group_id=${encodeURIComponent(group_id)}` : "";
29773
29773
  return this.request("GET", `/v1/apps/${encodeURIComponent(app_id)}/members${qs}`);
29774
29774
  }
29775
+ /**
29776
+ * Resolve the full option set (key, label, color) of a named query's select
29777
+ * columns — the picker companion to `appQuery`. Mirrors
29778
+ * POST /v1/apps/{app_id}/field-options.
29779
+ */
29780
+ async appFieldOptions(app_id, alias) {
29781
+ return this.request("POST", `/v1/apps/${encodeURIComponent(app_id)}/field-options`, { alias });
29782
+ }
29775
29783
  /**
29776
29784
  * Execute a workflow by alias declared in package.json#lotics.workflows.
29777
29785
  * Mirrors POST /v1/apps/{app_id}/workflows/{alias}/execute.
@@ -30720,6 +30728,7 @@ import { spawn } from "node:child_process";
30720
30728
  // src/dev/rpc_handler.ts
30721
30729
  var SUPPORTED_OPS = /* @__PURE__ */ new Set([
30722
30730
  "query",
30731
+ "field_options",
30723
30732
  "workflow",
30724
30733
  "members",
30725
30734
  "context",
@@ -30761,6 +30770,13 @@ async function dispatchRpc(client, body, opts) {
30761
30770
  count: p.count
30762
30771
  });
30763
30772
  }
30773
+ case "field_options": {
30774
+ const p = body.payload;
30775
+ if (!p || typeof p.alias !== "string") {
30776
+ throw new Error("field_options payload must include `alias`");
30777
+ }
30778
+ return client.appFieldOptions(body.app_id, p.alias);
30779
+ }
30764
30780
  case "workflow": {
30765
30781
  const p = body.payload;
30766
30782
  if (!p || typeof p.alias !== "string") {
@@ -47578,6 +47594,8 @@ COMMANDS
47578
47594
  lotics tools List all available tools
47579
47595
  lotics tools <name> Show tool description and input schema
47580
47596
  lotics run <tool> '<json>' Execute a tool
47597
+ lotics run <tool> @args.json Read JSON args from a file (large payloads)
47598
+ cat args.json | lotics run <tool> Read JSON args from stdin (large payloads)
47581
47599
  lotics upload <file|dir...> Upload files (directories expand to their immediate files)
47582
47600
  lotics download <file_id> Download a file by ID
47583
47601
  lotics download record <record_id> <field_key>
@@ -48022,7 +48040,9 @@ async function main() {
48022
48040
  process.exit(1);
48023
48041
  }
48024
48042
  if (command === "run" && !subcommand) {
48025
- console.error("Usage: lotics run <tool> '<json_args>'");
48043
+ console.error(
48044
+ "Usage: lotics run <tool> '<json_args>'\n lotics run <tool> @args.json (read args from a file \u2014 for large payloads)\n cat args.json | lotics run <tool> (read args from stdin)"
48045
+ );
48026
48046
  console.error('Run "lotics tools" to see available tools.');
48027
48047
  process.exit(1);
48028
48048
  }
@@ -48254,7 +48274,17 @@ ${JSON.stringify(info.input_schema, null, 2)}`);
48254
48274
  if (command === "run") {
48255
48275
  const toolName = subcommand;
48256
48276
  let rawArgs = toolArgs;
48257
- if (!rawArgs && !process.stdin.isTTY) {
48277
+ if (rawArgs && rawArgs.startsWith("@")) {
48278
+ const argsPath = rawArgs.slice(1);
48279
+ try {
48280
+ rawArgs = fs7.readFileSync(argsPath, "utf-8");
48281
+ } catch (err2) {
48282
+ console.error(
48283
+ `Cannot read args file "${argsPath}": ${err2 instanceof Error ? err2.message : String(err2)}`
48284
+ );
48285
+ process.exit(1);
48286
+ }
48287
+ } else if (!rawArgs && !process.stdin.isTTY) {
48258
48288
  rawArgs = await readStdin();
48259
48289
  }
48260
48290
  let args = {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lotics/cli",
3
- "version": "0.47.0",
3
+ "version": "0.49.0",
4
4
  "description": "Lotics SDK and CLI for AI agents",
5
5
  "type": "module",
6
6
  "bin": {