@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 +4 -1
- package/dist/cli.js +22 -2
- package/dist/client.d.ts +15 -0
- package/dist/client.js +8 -0
- package/dist/dev/rpc_handler.d.ts +1 -1
- package/dist/dev/rpc_handler.js +8 -0
- package/dist/dev/rpc_handler.test.js +21 -0
- package/dist/src/cli.js +32 -2
- package/package.json +1 -1
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
|
-
#
|
|
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(
|
|
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 (
|
|
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;
|
package/dist/dev/rpc_handler.js
CHANGED
|
@@ -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(
|
|
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 (
|
|
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 = {};
|