@kweaver-ai/kweaver-sdk 0.6.4 → 0.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -1
- package/dist/api/dataflow.d.ts +1 -1
- package/dist/api/toolboxes.d.ts +47 -0
- package/dist/api/toolboxes.js +90 -0
- package/dist/cli.js +19 -0
- package/dist/commands/bkn-ops.d.ts +1 -0
- package/dist/commands/bkn-ops.js +8 -1
- package/dist/commands/call.d.ts +10 -0
- package/dist/commands/call.js +61 -5
- package/dist/commands/ds.js +1 -1
- package/dist/commands/import-csv.d.ts +1 -1
- package/dist/commands/import-csv.js +3 -1
- package/dist/commands/tool.d.ts +16 -0
- package/dist/commands/tool.js +208 -0
- package/dist/commands/toolbox.d.ts +14 -0
- package/dist/commands/toolbox.js +256 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -180,7 +180,9 @@ kweaver skill list/market/get/register/status/delete/content/read-file/download/
|
|
|
180
180
|
kweaver vega health/stats/inspect/sql/catalog/resource/connector-type
|
|
181
181
|
kweaver context-loader config set/use/list/show
|
|
182
182
|
kweaver context-loader kn-search/query-object-instance/...
|
|
183
|
-
kweaver
|
|
183
|
+
kweaver toolbox create/list/publish/unpublish/delete
|
|
184
|
+
kweaver tool upload/list/enable/disable
|
|
185
|
+
kweaver call <path> [-X METHOD] [-d BODY] [-H header] [-F key=value]
|
|
184
186
|
```
|
|
185
187
|
|
|
186
188
|
### Dataflow CLI examples
|
|
@@ -211,6 +213,25 @@ kweaver vega sql -d '{"resource_type":"mysql","query":"SELECT * FROM {{res-1}} L
|
|
|
211
213
|
|
|
212
214
|
If both `-d` and `--query` / `--resource-type` are present, **only `-d` is used**.
|
|
213
215
|
|
|
216
|
+
### Register an Agent toolbox
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
# 1. Create a toolbox pointing at your service
|
|
220
|
+
kweaver toolbox create \
|
|
221
|
+
--name my_actions \
|
|
222
|
+
--service-url http://my-svc:8080 \
|
|
223
|
+
--description "Demo action backend"
|
|
224
|
+
# → {"box_id":"<BOX_ID>"}
|
|
225
|
+
|
|
226
|
+
# 2. Upload an OpenAPI spec as a tool
|
|
227
|
+
kweaver tool upload --toolbox <BOX_ID> ./openapi.json
|
|
228
|
+
# → {"success_ids":["<TOOL_ID>"]}
|
|
229
|
+
|
|
230
|
+
# 3. Publish the toolbox and enable the tool
|
|
231
|
+
kweaver toolbox publish <BOX_ID>
|
|
232
|
+
kweaver tool enable --toolbox <BOX_ID> <TOOL_ID>
|
|
233
|
+
```
|
|
234
|
+
|
|
214
235
|
**No-auth platforms:** If OAuth is not enabled, use `kweaver auth <url> --no-auth` (or run a normal `auth login`; a **404** on `POST /oauth2/clients` switches to no-auth automatically). Credentials are still saved under `~/.kweaver/` and work with `auth use` / `auth list`. Optional: `KWEAVER_NO_AUTH=1` with `KWEAVER_BASE_URL` when no token env is set. SDK: `new KWeaverClient({ baseUrl, auth: false })` or `kweaver.configure({ baseUrl, auth: false })`.
|
|
215
236
|
|
|
216
237
|
## Environment Variables
|
package/dist/api/dataflow.d.ts
CHANGED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
interface BaseOpts {
|
|
2
|
+
baseUrl: string;
|
|
3
|
+
accessToken: string;
|
|
4
|
+
businessDomain?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface CreateToolboxOptions extends BaseOpts {
|
|
7
|
+
name: string;
|
|
8
|
+
description: string;
|
|
9
|
+
serviceUrl: string;
|
|
10
|
+
metadataType?: "openapi";
|
|
11
|
+
source?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function createToolbox(opts: CreateToolboxOptions): Promise<string>;
|
|
14
|
+
export interface DeleteToolboxOptions extends BaseOpts {
|
|
15
|
+
boxId: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function deleteToolbox(opts: DeleteToolboxOptions): Promise<void>;
|
|
18
|
+
export interface SetToolboxStatusOptions extends BaseOpts {
|
|
19
|
+
boxId: string;
|
|
20
|
+
status: "published" | "draft";
|
|
21
|
+
}
|
|
22
|
+
export declare function setToolboxStatus(opts: SetToolboxStatusOptions): Promise<void>;
|
|
23
|
+
export interface UploadToolOptions extends BaseOpts {
|
|
24
|
+
boxId: string;
|
|
25
|
+
filePath: string;
|
|
26
|
+
metadataType?: "openapi";
|
|
27
|
+
}
|
|
28
|
+
export declare function uploadTool(opts: UploadToolOptions): Promise<string>;
|
|
29
|
+
export interface SetToolStatusesOptions extends BaseOpts {
|
|
30
|
+
boxId: string;
|
|
31
|
+
updates: Array<{
|
|
32
|
+
toolId: string;
|
|
33
|
+
status: "enabled" | "disabled";
|
|
34
|
+
}>;
|
|
35
|
+
}
|
|
36
|
+
export declare function setToolStatuses(opts: SetToolStatusesOptions): Promise<void>;
|
|
37
|
+
export interface ListToolboxesOptions extends BaseOpts {
|
|
38
|
+
keyword?: string;
|
|
39
|
+
limit?: number;
|
|
40
|
+
offset?: number;
|
|
41
|
+
}
|
|
42
|
+
export declare function listToolboxes(opts: ListToolboxesOptions): Promise<string>;
|
|
43
|
+
export interface ListToolsOptions extends BaseOpts {
|
|
44
|
+
boxId: string;
|
|
45
|
+
}
|
|
46
|
+
export declare function listTools(opts: ListToolsOptions): Promise<string>;
|
|
47
|
+
export {};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { basename } from "node:path";
|
|
3
|
+
import { fetchTextOrThrow } from "../utils/http.js";
|
|
4
|
+
import { buildHeaders } from "./headers.js";
|
|
5
|
+
// Backend endpoints under /api/agent-operator-integration/v1/tool-box.
|
|
6
|
+
//
|
|
7
|
+
// Verified against kweaver/examples/03-action-lifecycle/run.sh (lines 78–197):
|
|
8
|
+
// POST /tool-box create
|
|
9
|
+
// DELETE /tool-box/{id} delete
|
|
10
|
+
// POST /tool-box/{id}/status publish/draft
|
|
11
|
+
// POST /tool-box/{id}/tool upload tool (multipart)
|
|
12
|
+
// POST /tool-box/{id}/tools/status enable/disable (batch)
|
|
13
|
+
//
|
|
14
|
+
// Verified during Task 8 e2e against the live backend (2026-04-18):
|
|
15
|
+
// GET /tool-box?keyword=&limit=&offset= list toolboxes
|
|
16
|
+
// GET /tool-box/{id}/tool list tools
|
|
17
|
+
const PATH = "/api/agent-operator-integration/v1/tool-box";
|
|
18
|
+
function url(base, suffix = "") {
|
|
19
|
+
return `${base.replace(/\/+$/, "")}${PATH}${suffix}`;
|
|
20
|
+
}
|
|
21
|
+
export async function createToolbox(opts) {
|
|
22
|
+
const body = JSON.stringify({
|
|
23
|
+
metadata_type: opts.metadataType ?? "openapi",
|
|
24
|
+
box_name: opts.name,
|
|
25
|
+
box_desc: opts.description,
|
|
26
|
+
box_svc_url: opts.serviceUrl,
|
|
27
|
+
source: opts.source ?? "custom",
|
|
28
|
+
});
|
|
29
|
+
const { body: text } = await fetchTextOrThrow(url(opts.baseUrl), {
|
|
30
|
+
method: "POST",
|
|
31
|
+
headers: { ...buildHeaders(opts.accessToken, opts.businessDomain ?? "bd_public"), "content-type": "application/json" },
|
|
32
|
+
body,
|
|
33
|
+
});
|
|
34
|
+
return text;
|
|
35
|
+
}
|
|
36
|
+
export async function deleteToolbox(opts) {
|
|
37
|
+
await fetchTextOrThrow(url(opts.baseUrl, `/${encodeURIComponent(opts.boxId)}`), {
|
|
38
|
+
method: "DELETE",
|
|
39
|
+
headers: buildHeaders(opts.accessToken, opts.businessDomain ?? "bd_public"),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
export async function setToolboxStatus(opts) {
|
|
43
|
+
await fetchTextOrThrow(url(opts.baseUrl, `/${encodeURIComponent(opts.boxId)}/status`), {
|
|
44
|
+
method: "POST",
|
|
45
|
+
headers: { ...buildHeaders(opts.accessToken, opts.businessDomain ?? "bd_public"), "content-type": "application/json" },
|
|
46
|
+
body: JSON.stringify({ status: opts.status }),
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
export async function uploadTool(opts) {
|
|
50
|
+
const buf = await readFile(opts.filePath);
|
|
51
|
+
const form = new FormData();
|
|
52
|
+
form.append("metadata_type", opts.metadataType ?? "openapi");
|
|
53
|
+
form.append("data", new Blob([buf]), basename(opts.filePath));
|
|
54
|
+
const { body: text } = await fetchTextOrThrow(url(opts.baseUrl, `/${encodeURIComponent(opts.boxId)}/tool`), {
|
|
55
|
+
method: "POST",
|
|
56
|
+
headers: buildHeaders(opts.accessToken, opts.businessDomain ?? "bd_public"),
|
|
57
|
+
body: form,
|
|
58
|
+
});
|
|
59
|
+
return text;
|
|
60
|
+
}
|
|
61
|
+
export async function setToolStatuses(opts) {
|
|
62
|
+
const body = JSON.stringify(opts.updates.map((u) => ({ tool_id: u.toolId, status: u.status })));
|
|
63
|
+
await fetchTextOrThrow(url(opts.baseUrl, `/${encodeURIComponent(opts.boxId)}/tools/status`), {
|
|
64
|
+
method: "POST",
|
|
65
|
+
headers: { ...buildHeaders(opts.accessToken, opts.businessDomain ?? "bd_public"), "content-type": "application/json" },
|
|
66
|
+
body,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
export async function listToolboxes(opts) {
|
|
70
|
+
const qp = new URLSearchParams();
|
|
71
|
+
if (opts.keyword !== undefined)
|
|
72
|
+
qp.set("keyword", opts.keyword);
|
|
73
|
+
if (opts.limit !== undefined)
|
|
74
|
+
qp.set("limit", String(opts.limit));
|
|
75
|
+
if (opts.offset !== undefined)
|
|
76
|
+
qp.set("offset", String(opts.offset));
|
|
77
|
+
const suffix = qp.toString() ? `?${qp}` : "";
|
|
78
|
+
const { body } = await fetchTextOrThrow(url(opts.baseUrl, suffix), {
|
|
79
|
+
method: "GET",
|
|
80
|
+
headers: buildHeaders(opts.accessToken, opts.businessDomain ?? "bd_public"),
|
|
81
|
+
});
|
|
82
|
+
return body;
|
|
83
|
+
}
|
|
84
|
+
export async function listTools(opts) {
|
|
85
|
+
const { body } = await fetchTextOrThrow(url(opts.baseUrl, `/${encodeURIComponent(opts.boxId)}/tool`), {
|
|
86
|
+
method: "GET",
|
|
87
|
+
headers: buildHeaders(opts.accessToken, opts.businessDomain ?? "bd_public"),
|
|
88
|
+
});
|
|
89
|
+
return body;
|
|
90
|
+
}
|
package/dist/cli.js
CHANGED
|
@@ -12,6 +12,8 @@ import { runExploreCommand } from "./commands/explore.js";
|
|
|
12
12
|
import { runDataviewCommand } from "./commands/dataview.js";
|
|
13
13
|
import { runSkillCommand } from "./commands/skill.js";
|
|
14
14
|
import { runTokenCommand } from "./commands/token.js";
|
|
15
|
+
import { runToolboxCommand } from "./commands/toolbox.js";
|
|
16
|
+
import { runToolCommand } from "./commands/tool.js";
|
|
15
17
|
import { runVegaCommand } from "./commands/vega.js";
|
|
16
18
|
function printHelp() {
|
|
17
19
|
console.log(`kweaver
|
|
@@ -99,6 +101,15 @@ Usage:
|
|
|
99
101
|
kweaver skill read-file <skill-id> <rel-path> [--raw] [--output file]
|
|
100
102
|
kweaver skill download|install <skill-id> [path] [options]
|
|
101
103
|
|
|
104
|
+
kweaver toolbox create --name <n> --service-url <url> [--description <d>] [-bd value]
|
|
105
|
+
kweaver toolbox list [--keyword X] [--limit N] [--offset N] [-bd value]
|
|
106
|
+
kweaver toolbox publish|unpublish <box-id> [-bd value]
|
|
107
|
+
kweaver toolbox delete <box-id> [-y] [-bd value]
|
|
108
|
+
|
|
109
|
+
kweaver tool upload --toolbox <box-id> <openapi-spec-path> [--metadata-type openapi]
|
|
110
|
+
kweaver tool list --toolbox <box-id> [-bd value]
|
|
111
|
+
kweaver tool enable|disable --toolbox <box-id> <tool-id>... [-bd value]
|
|
112
|
+
|
|
102
113
|
kweaver vega health|stats|inspect
|
|
103
114
|
kweaver vega catalog list|get|health|test-connection|discover|resources [options]
|
|
104
115
|
kweaver vega resource list|get|query [options]
|
|
@@ -129,6 +140,8 @@ Commands:
|
|
|
129
140
|
object-type, relation-type, subgraph, action-type, action-execution, action-log)
|
|
130
141
|
config Per-platform configuration (business domain)
|
|
131
142
|
skill Skill registry and market (register, search, progressive read, download/install)
|
|
143
|
+
toolbox Agent toolbox lifecycle (create, list, publish, delete)
|
|
144
|
+
tool Tools inside a toolbox (upload OpenAPI spec, list, enable/disable)
|
|
132
145
|
vega Vega observability (catalog, resource, query/sql, connector-type, health/stats/inspect)
|
|
133
146
|
context-loader Context-loader MCP (config, tools, resources, prompts, kn-search, query-*, etc.)
|
|
134
147
|
help Show this message`);
|
|
@@ -195,6 +208,12 @@ export async function run(argv) {
|
|
|
195
208
|
if (command === "skill") {
|
|
196
209
|
return runSkillCommand(rest);
|
|
197
210
|
}
|
|
211
|
+
if (command === "toolbox") {
|
|
212
|
+
return runToolboxCommand(rest);
|
|
213
|
+
}
|
|
214
|
+
if (command === "tool") {
|
|
215
|
+
return runToolCommand(rest);
|
|
216
|
+
}
|
|
198
217
|
if (command === "context-loader" || command === "context") {
|
|
199
218
|
return runContextLoaderCommand(rest);
|
|
200
219
|
}
|
package/dist/commands/bkn-ops.js
CHANGED
|
@@ -706,6 +706,7 @@ Options:
|
|
|
706
706
|
--tables <a,b> Tables to include in KN (default: all imported)
|
|
707
707
|
--build (default) Build after creation
|
|
708
708
|
--no-build Skip build
|
|
709
|
+
--recreate Use "insert" mode on first batch (only effective for new tables)
|
|
709
710
|
--timeout <n> Build timeout in seconds (default: 300)
|
|
710
711
|
-bd, --biz-domain Business domain (default: bd_public)`;
|
|
711
712
|
export function parseKnCreateFromCsvArgs(args) {
|
|
@@ -716,6 +717,7 @@ export function parseKnCreateFromCsvArgs(args) {
|
|
|
716
717
|
let batchSize = 500;
|
|
717
718
|
let tablesStr = "";
|
|
718
719
|
let build = true;
|
|
720
|
+
let recreate = false;
|
|
719
721
|
let timeout = 300;
|
|
720
722
|
let businessDomain = "";
|
|
721
723
|
for (let i = 0; i < args.length; i += 1) {
|
|
@@ -752,6 +754,10 @@ export function parseKnCreateFromCsvArgs(args) {
|
|
|
752
754
|
build = false;
|
|
753
755
|
continue;
|
|
754
756
|
}
|
|
757
|
+
if (arg === "--recreate") {
|
|
758
|
+
recreate = true;
|
|
759
|
+
continue;
|
|
760
|
+
}
|
|
755
761
|
if (arg === "--timeout" && args[i + 1]) {
|
|
756
762
|
timeout = parseInt(args[++i], 10);
|
|
757
763
|
if (Number.isNaN(timeout) || timeout < 1)
|
|
@@ -772,7 +778,7 @@ export function parseKnCreateFromCsvArgs(args) {
|
|
|
772
778
|
}
|
|
773
779
|
if (!businessDomain)
|
|
774
780
|
businessDomain = resolveBusinessDomain();
|
|
775
|
-
return { dsId, files, name, tablePrefix, batchSize, tables, build, timeout, businessDomain };
|
|
781
|
+
return { dsId, files, name, tablePrefix, batchSize, tables, build, recreate, timeout, businessDomain };
|
|
776
782
|
}
|
|
777
783
|
export async function runKnCreateFromCsvCommand(args) {
|
|
778
784
|
let options;
|
|
@@ -795,6 +801,7 @@ export async function runKnCreateFromCsvCommand(args) {
|
|
|
795
801
|
"--table-prefix", options.tablePrefix,
|
|
796
802
|
"--batch-size", String(options.batchSize),
|
|
797
803
|
"-bd", options.businessDomain,
|
|
804
|
+
...(options.recreate ? ["--recreate"] : []),
|
|
798
805
|
];
|
|
799
806
|
const importResult = await runDsImportCsv(importArgs);
|
|
800
807
|
if (importResult.code !== 0) {
|
package/dist/commands/call.d.ts
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
|
+
export type FormField = {
|
|
2
|
+
name: string;
|
|
3
|
+
kind: "string";
|
|
4
|
+
value: string;
|
|
5
|
+
} | {
|
|
6
|
+
name: string;
|
|
7
|
+
kind: "file";
|
|
8
|
+
path: string;
|
|
9
|
+
};
|
|
1
10
|
export interface CallInvocation {
|
|
2
11
|
url: string;
|
|
3
12
|
method: string;
|
|
4
13
|
headers: Headers;
|
|
5
14
|
body?: string;
|
|
15
|
+
formFields?: FormField[];
|
|
6
16
|
pretty: boolean;
|
|
7
17
|
verbose: boolean;
|
|
8
18
|
businessDomain: string;
|
package/dist/commands/call.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { basename } from "node:path";
|
|
1
3
|
import { ensureValidToken, formatHttpError, with401RefreshRetry } from "../auth/oauth.js";
|
|
2
4
|
import { isNoAuth } from "../config/no-auth.js";
|
|
3
5
|
import { HttpError } from "../utils/http.js";
|
|
@@ -6,6 +8,7 @@ export function parseCallArgs(args) {
|
|
|
6
8
|
const headers = new Headers();
|
|
7
9
|
let method = "GET";
|
|
8
10
|
let body;
|
|
11
|
+
const formFields = [];
|
|
9
12
|
let url;
|
|
10
13
|
let pretty = true;
|
|
11
14
|
let verbose = false;
|
|
@@ -40,6 +43,26 @@ export function parseCallArgs(args) {
|
|
|
40
43
|
index += 1;
|
|
41
44
|
continue;
|
|
42
45
|
}
|
|
46
|
+
if (arg === "-F" || arg === "--form") {
|
|
47
|
+
const raw = args[index + 1];
|
|
48
|
+
if (!raw)
|
|
49
|
+
throw new Error("Missing value for -F flag");
|
|
50
|
+
const eq = raw.indexOf("=");
|
|
51
|
+
if (eq === -1)
|
|
52
|
+
throw new Error(`Invalid -F format: ${raw} (expected key=value or key=@path)`);
|
|
53
|
+
const name = raw.slice(0, eq);
|
|
54
|
+
const rhs = raw.slice(eq + 1);
|
|
55
|
+
if (rhs.startsWith("@")) {
|
|
56
|
+
formFields.push({ name, kind: "file", path: rhs.slice(1) });
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
formFields.push({ name, kind: "string", value: rhs });
|
|
60
|
+
}
|
|
61
|
+
if (method === "GET")
|
|
62
|
+
method = "POST";
|
|
63
|
+
index += 1;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
43
66
|
if (arg === "--pretty") {
|
|
44
67
|
pretty = true;
|
|
45
68
|
continue;
|
|
@@ -70,9 +93,21 @@ export function parseCallArgs(args) {
|
|
|
70
93
|
if (!url) {
|
|
71
94
|
throw new Error("Missing request URL");
|
|
72
95
|
}
|
|
96
|
+
if (formFields.length > 0 && body !== undefined) {
|
|
97
|
+
throw new Error("-F and -d are mutually exclusive");
|
|
98
|
+
}
|
|
73
99
|
if (!businessDomain)
|
|
74
100
|
businessDomain = resolveBusinessDomain();
|
|
75
|
-
return {
|
|
101
|
+
return {
|
|
102
|
+
url,
|
|
103
|
+
method,
|
|
104
|
+
headers,
|
|
105
|
+
body,
|
|
106
|
+
formFields: formFields.length > 0 ? formFields : undefined,
|
|
107
|
+
pretty,
|
|
108
|
+
verbose,
|
|
109
|
+
businessDomain,
|
|
110
|
+
};
|
|
76
111
|
}
|
|
77
112
|
function injectAuthHeaders(headers, accessToken, businessDomain) {
|
|
78
113
|
if (!isNoAuth(accessToken)) {
|
|
@@ -115,12 +150,17 @@ export function formatVerboseRequest(invocation) {
|
|
|
115
150
|
for (const [name, value] of entries) {
|
|
116
151
|
lines.push(` ${name}: ${value}`);
|
|
117
152
|
}
|
|
118
|
-
|
|
153
|
+
const bodyDesc = invocation.formFields && invocation.formFields.length > 0
|
|
154
|
+
? `multipart (${invocation.formFields.length} field${invocation.formFields.length > 1 ? "s" : ""})`
|
|
155
|
+
: invocation.body
|
|
156
|
+
? "present"
|
|
157
|
+
: "empty";
|
|
158
|
+
lines.push(`Body: ${bodyDesc}`);
|
|
119
159
|
return lines;
|
|
120
160
|
}
|
|
121
161
|
export async function runCallCommand(args) {
|
|
122
162
|
if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
|
|
123
|
-
console.log(`kweaver call <url> [-X METHOD] [-H "Name: value"] [-d BODY] [--pretty] [--verbose] [-bd value]
|
|
163
|
+
console.log(`kweaver call <url> [-X METHOD] [-H "Name: value"] [-d BODY] [-F key=value] [--pretty] [--verbose] [-bd value]
|
|
124
164
|
|
|
125
165
|
Call an API with curl-style flags and auto-injected token headers.
|
|
126
166
|
|
|
@@ -129,6 +169,7 @@ Options:
|
|
|
129
169
|
-X, --request HTTP method (default: GET)
|
|
130
170
|
-H, --header Extra header (repeatable)
|
|
131
171
|
-d, --data, --data-raw JSON request body (sets Content-Type: application/json if not set)
|
|
172
|
+
-F, --form Multipart form field. -F key=value or -F key=@/path/to/file. Repeatable. Mutually exclusive with -d.
|
|
132
173
|
-bd, --biz-domain Override x-business-domain (default: bd_public)
|
|
133
174
|
-v, --verbose Print request info to stderr
|
|
134
175
|
--pretty Pretty-print JSON output (default)`);
|
|
@@ -150,7 +191,22 @@ Options:
|
|
|
150
191
|
: invocation.url;
|
|
151
192
|
const headers = new Headers(invocation.headers);
|
|
152
193
|
injectAuthHeaders(headers, token.accessToken, invocation.businessDomain);
|
|
153
|
-
|
|
194
|
+
let requestBody = invocation.body;
|
|
195
|
+
if (invocation.formFields && invocation.formFields.length > 0) {
|
|
196
|
+
const form = new FormData();
|
|
197
|
+
for (const field of invocation.formFields) {
|
|
198
|
+
if (field.kind === "string") {
|
|
199
|
+
form.append(field.name, field.value);
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
const buf = await readFile(field.path);
|
|
203
|
+
form.append(field.name, new Blob([buf]), basename(field.path));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
requestBody = form;
|
|
207
|
+
// do not set content-type — fetch sets multipart boundary
|
|
208
|
+
}
|
|
209
|
+
else if (invocation.body !== undefined &&
|
|
154
210
|
invocation.body.length > 0 &&
|
|
155
211
|
!headers.has("content-type") &&
|
|
156
212
|
!headers.has("Content-Type")) {
|
|
@@ -164,7 +220,7 @@ Options:
|
|
|
164
220
|
const response = await fetch(url, {
|
|
165
221
|
method: invocation.method,
|
|
166
222
|
headers,
|
|
167
|
-
body:
|
|
223
|
+
body: requestBody,
|
|
168
224
|
});
|
|
169
225
|
const rawText = await response.text();
|
|
170
226
|
const text = stripSseDoneMarker(rawText, response.headers.get("content-type"));
|
package/dist/commands/ds.js
CHANGED
|
@@ -466,7 +466,7 @@ export async function runDsImportCsv(args) {
|
|
|
466
466
|
process.stderr.write(`${elapsed}s\n`);
|
|
467
467
|
}
|
|
468
468
|
catch (err) {
|
|
469
|
-
const msg =
|
|
469
|
+
const msg = formatHttpError(err);
|
|
470
470
|
process.stderr.write(`FAILED\n`);
|
|
471
471
|
console.error(`[${tableName}] batch ${batchLabel} error: ${msg}`);
|
|
472
472
|
batchFailed = true;
|
|
@@ -19,7 +19,7 @@ export interface DagBodyOptions {
|
|
|
19
19
|
tableExist: boolean;
|
|
20
20
|
data: Array<Record<string, string | null>>;
|
|
21
21
|
fieldMappings: FieldMapping[];
|
|
22
|
-
/** When true on the first batch (`tableExist` false), use
|
|
22
|
+
/** When true on the first batch (`tableExist` false), use "insert" to force table recreation. */
|
|
23
23
|
recreate?: boolean;
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
@@ -82,7 +82,9 @@ export function buildFieldMappings(headers) {
|
|
|
82
82
|
export function buildDagBody(options) {
|
|
83
83
|
const { datasourceId, datasourceType, tableName, tableExist, data, fieldMappings, recreate } = options;
|
|
84
84
|
const ts = Date.now();
|
|
85
|
-
|
|
85
|
+
// "insert" creates/replaces the table; "append" adds rows to an existing table.
|
|
86
|
+
// With --recreate, use "insert" on first batch to force table recreation when schema changed.
|
|
87
|
+
const operateType = tableExist ? "append" : recreate ? "insert" : "append";
|
|
86
88
|
const triggerStep = {
|
|
87
89
|
id: "step-trigger",
|
|
88
90
|
title: "Trigger",
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare function runToolCommand(args: string[]): Promise<number>;
|
|
2
|
+
export interface ToolUploadOptions {
|
|
3
|
+
boxId: string;
|
|
4
|
+
filePath: string;
|
|
5
|
+
metadataType: "openapi";
|
|
6
|
+
businessDomain: string;
|
|
7
|
+
pretty: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function parseToolUploadArgs(args: string[]): ToolUploadOptions;
|
|
10
|
+
export interface ToolStatusOptions {
|
|
11
|
+
boxId: string;
|
|
12
|
+
toolIds: string[];
|
|
13
|
+
status: "enabled" | "disabled";
|
|
14
|
+
businessDomain: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function parseToolStatusArgs(args: string[], status: "enabled" | "disabled"): ToolStatusOptions;
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { access } from "node:fs/promises";
|
|
2
|
+
import { ensureValidToken, formatHttpError, with401RefreshRetry } from "../auth/oauth.js";
|
|
3
|
+
import { listTools, setToolStatuses, uploadTool } from "../api/toolboxes.js";
|
|
4
|
+
import { formatCallOutput } from "./call.js";
|
|
5
|
+
import { resolveBusinessDomain } from "../config/store.js";
|
|
6
|
+
const HELP = `kweaver tool
|
|
7
|
+
|
|
8
|
+
Subcommands:
|
|
9
|
+
upload --toolbox <box-id> <openapi-spec-path> [--metadata-type openapi]
|
|
10
|
+
Upload an OpenAPI spec file as a tool
|
|
11
|
+
list --toolbox <box-id> List tools in a toolbox
|
|
12
|
+
enable --toolbox <box-id> <tool-id>... Enable one or more tools
|
|
13
|
+
disable --toolbox <box-id> <tool-id>... Disable one or more tools
|
|
14
|
+
|
|
15
|
+
Options:
|
|
16
|
+
-bd, --biz-domain <s> Business domain (default: bd_public)
|
|
17
|
+
--pretty Pretty-print JSON (default)
|
|
18
|
+
--compact Single-line JSON (pipeline-friendly)`;
|
|
19
|
+
export async function runToolCommand(args) {
|
|
20
|
+
const [subcommand, ...rest] = args;
|
|
21
|
+
if (!subcommand || subcommand === "--help" || subcommand === "-h") {
|
|
22
|
+
console.log(HELP);
|
|
23
|
+
return 0;
|
|
24
|
+
}
|
|
25
|
+
const dispatch = () => {
|
|
26
|
+
if (subcommand === "upload")
|
|
27
|
+
return runToolUpload(rest);
|
|
28
|
+
if (subcommand === "list")
|
|
29
|
+
return runToolList(rest);
|
|
30
|
+
if (subcommand === "enable")
|
|
31
|
+
return runToolStatus(rest, "enabled");
|
|
32
|
+
if (subcommand === "disable")
|
|
33
|
+
return runToolStatus(rest, "disabled");
|
|
34
|
+
return Promise.resolve(-1);
|
|
35
|
+
};
|
|
36
|
+
try {
|
|
37
|
+
return await with401RefreshRetry(async () => {
|
|
38
|
+
const code = await dispatch();
|
|
39
|
+
if (code === -1) {
|
|
40
|
+
console.error(`Unknown tool subcommand: ${subcommand}`);
|
|
41
|
+
return 1;
|
|
42
|
+
}
|
|
43
|
+
return code;
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
console.error(formatHttpError(error));
|
|
48
|
+
return 1;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export function parseToolUploadArgs(args) {
|
|
52
|
+
let boxId = "";
|
|
53
|
+
let filePath = "";
|
|
54
|
+
let metadataType = "openapi";
|
|
55
|
+
let businessDomain = "";
|
|
56
|
+
let pretty = true;
|
|
57
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
58
|
+
const a = args[i];
|
|
59
|
+
if (a === "--toolbox" && args[i + 1]) {
|
|
60
|
+
boxId = args[++i];
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (a === "--metadata-type" && args[i + 1]) {
|
|
64
|
+
const val = args[++i];
|
|
65
|
+
if (val !== "openapi") {
|
|
66
|
+
throw new Error(`Unsupported --metadata-type: ${val} (only "openapi" is supported)`);
|
|
67
|
+
}
|
|
68
|
+
metadataType = val;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if ((a === "-bd" || a === "--biz-domain") && args[i + 1]) {
|
|
72
|
+
businessDomain = args[++i];
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (a === "--pretty") {
|
|
76
|
+
pretty = true;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (a === "--compact") {
|
|
80
|
+
pretty = false;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (!a.startsWith("-") && !filePath) {
|
|
84
|
+
filePath = a;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (!boxId)
|
|
89
|
+
throw new Error("Missing required flag: --toolbox");
|
|
90
|
+
if (!filePath)
|
|
91
|
+
throw new Error("Missing required positional argument: <file-path>");
|
|
92
|
+
if (!businessDomain)
|
|
93
|
+
businessDomain = resolveBusinessDomain();
|
|
94
|
+
return { boxId, filePath, metadataType, businessDomain, pretty };
|
|
95
|
+
}
|
|
96
|
+
async function runToolUpload(args) {
|
|
97
|
+
let opts;
|
|
98
|
+
try {
|
|
99
|
+
opts = parseToolUploadArgs(args);
|
|
100
|
+
}
|
|
101
|
+
catch (e) {
|
|
102
|
+
console.error(e instanceof Error ? e.message : String(e));
|
|
103
|
+
return 1;
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
await access(opts.filePath);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
console.error(`File not found: ${opts.filePath}`);
|
|
110
|
+
return 1;
|
|
111
|
+
}
|
|
112
|
+
const token = await ensureValidToken();
|
|
113
|
+
const body = await uploadTool({
|
|
114
|
+
baseUrl: token.baseUrl,
|
|
115
|
+
accessToken: token.accessToken,
|
|
116
|
+
businessDomain: opts.businessDomain,
|
|
117
|
+
boxId: opts.boxId,
|
|
118
|
+
filePath: opts.filePath,
|
|
119
|
+
metadataType: opts.metadataType,
|
|
120
|
+
});
|
|
121
|
+
console.log(formatCallOutput(body, opts.pretty));
|
|
122
|
+
return 0;
|
|
123
|
+
}
|
|
124
|
+
// ── list ──────────────────────────────────────────────────────────────────────
|
|
125
|
+
async function runToolList(args) {
|
|
126
|
+
let boxId = "";
|
|
127
|
+
let businessDomain = "";
|
|
128
|
+
let pretty = true;
|
|
129
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
130
|
+
const a = args[i];
|
|
131
|
+
if (a === "--toolbox" && args[i + 1]) {
|
|
132
|
+
boxId = args[++i];
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if ((a === "-bd" || a === "--biz-domain") && args[i + 1]) {
|
|
136
|
+
businessDomain = args[++i];
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if (a === "--pretty") {
|
|
140
|
+
pretty = true;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (a === "--compact") {
|
|
144
|
+
pretty = false;
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (!boxId) {
|
|
149
|
+
console.error("Missing required flag: --toolbox");
|
|
150
|
+
return 1;
|
|
151
|
+
}
|
|
152
|
+
if (!businessDomain)
|
|
153
|
+
businessDomain = resolveBusinessDomain();
|
|
154
|
+
const token = await ensureValidToken();
|
|
155
|
+
const body = await listTools({
|
|
156
|
+
baseUrl: token.baseUrl,
|
|
157
|
+
accessToken: token.accessToken,
|
|
158
|
+
businessDomain,
|
|
159
|
+
boxId,
|
|
160
|
+
});
|
|
161
|
+
console.log(formatCallOutput(body, pretty));
|
|
162
|
+
return 0;
|
|
163
|
+
}
|
|
164
|
+
export function parseToolStatusArgs(args, status) {
|
|
165
|
+
let boxId = "";
|
|
166
|
+
let businessDomain = "";
|
|
167
|
+
const toolIds = [];
|
|
168
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
169
|
+
const a = args[i];
|
|
170
|
+
if (a === "--toolbox" && args[i + 1]) {
|
|
171
|
+
boxId = args[++i];
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if ((a === "-bd" || a === "--biz-domain") && args[i + 1]) {
|
|
175
|
+
businessDomain = args[++i];
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
if (!a.startsWith("-"))
|
|
179
|
+
toolIds.push(a);
|
|
180
|
+
}
|
|
181
|
+
if (!boxId)
|
|
182
|
+
throw new Error("Missing required flag: --toolbox");
|
|
183
|
+
if (toolIds.length === 0)
|
|
184
|
+
throw new Error("Missing tool id(s)");
|
|
185
|
+
if (!businessDomain)
|
|
186
|
+
businessDomain = resolveBusinessDomain();
|
|
187
|
+
return { boxId, toolIds, status, businessDomain };
|
|
188
|
+
}
|
|
189
|
+
async function runToolStatus(args, status) {
|
|
190
|
+
let opts;
|
|
191
|
+
try {
|
|
192
|
+
opts = parseToolStatusArgs(args, status);
|
|
193
|
+
}
|
|
194
|
+
catch (e) {
|
|
195
|
+
console.error(e instanceof Error ? e.message : String(e));
|
|
196
|
+
return 1;
|
|
197
|
+
}
|
|
198
|
+
const token = await ensureValidToken();
|
|
199
|
+
await setToolStatuses({
|
|
200
|
+
baseUrl: token.baseUrl,
|
|
201
|
+
accessToken: token.accessToken,
|
|
202
|
+
businessDomain: opts.businessDomain,
|
|
203
|
+
boxId: opts.boxId,
|
|
204
|
+
updates: opts.toolIds.map((toolId) => ({ toolId, status: opts.status })),
|
|
205
|
+
});
|
|
206
|
+
console.error(`${status === "enabled" ? "Enabled" : "Disabled"} ${opts.toolIds.length} tool(s) in toolbox ${opts.boxId}`);
|
|
207
|
+
return 0;
|
|
208
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare function runToolboxCommand(args: string[]): Promise<number>;
|
|
2
|
+
export interface ToolboxCreateOptions {
|
|
3
|
+
name: string;
|
|
4
|
+
serviceUrl: string;
|
|
5
|
+
description: string;
|
|
6
|
+
businessDomain: string;
|
|
7
|
+
pretty: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function parseToolboxCreateArgs(args: string[]): ToolboxCreateOptions;
|
|
10
|
+
export interface ToolboxSetStatusOptions {
|
|
11
|
+
boxId: string;
|
|
12
|
+
businessDomain: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function parseToolboxSetStatusArgs(args: string[]): ToolboxSetStatusOptions;
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { createInterface } from "node:readline";
|
|
2
|
+
import { ensureValidToken, formatHttpError, with401RefreshRetry } from "../auth/oauth.js";
|
|
3
|
+
import { createToolbox, deleteToolbox, listToolboxes, setToolboxStatus } from "../api/toolboxes.js";
|
|
4
|
+
import { formatCallOutput } from "./call.js";
|
|
5
|
+
import { resolveBusinessDomain } from "../config/store.js";
|
|
6
|
+
const HELP = `kweaver toolbox
|
|
7
|
+
|
|
8
|
+
Subcommands:
|
|
9
|
+
create --name <n> --service-url <url> [--description <d>] Create a new toolbox
|
|
10
|
+
list [--keyword <s>] [--limit <n>] [--offset <n>] List toolboxes
|
|
11
|
+
publish <box-id> Publish a toolbox (status=published)
|
|
12
|
+
unpublish <box-id> Unpublish (status=draft)
|
|
13
|
+
delete <box-id> [-y|--yes] Delete a toolbox
|
|
14
|
+
|
|
15
|
+
Options:
|
|
16
|
+
-bd, --biz-domain <s> Business domain (default: bd_public)
|
|
17
|
+
--pretty Pretty-print JSON (default)
|
|
18
|
+
--compact Single-line JSON (pipeline-friendly)`;
|
|
19
|
+
export async function runToolboxCommand(args) {
|
|
20
|
+
const [subcommand, ...rest] = args;
|
|
21
|
+
if (!subcommand || subcommand === "--help" || subcommand === "-h") {
|
|
22
|
+
console.log(HELP);
|
|
23
|
+
return 0;
|
|
24
|
+
}
|
|
25
|
+
const dispatch = () => {
|
|
26
|
+
if (subcommand === "create")
|
|
27
|
+
return runToolboxCreate(rest);
|
|
28
|
+
if (subcommand === "list")
|
|
29
|
+
return runToolboxList(rest);
|
|
30
|
+
if (subcommand === "publish")
|
|
31
|
+
return runToolboxSetStatus(rest, "published");
|
|
32
|
+
if (subcommand === "unpublish")
|
|
33
|
+
return runToolboxSetStatus(rest, "draft");
|
|
34
|
+
if (subcommand === "delete")
|
|
35
|
+
return runToolboxDelete(rest);
|
|
36
|
+
return Promise.resolve(-1);
|
|
37
|
+
};
|
|
38
|
+
try {
|
|
39
|
+
return await with401RefreshRetry(async () => {
|
|
40
|
+
const code = await dispatch();
|
|
41
|
+
if (code === -1) {
|
|
42
|
+
console.error(`Unknown toolbox subcommand: ${subcommand}`);
|
|
43
|
+
return 1;
|
|
44
|
+
}
|
|
45
|
+
return code;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
console.error(formatHttpError(error));
|
|
50
|
+
return 1;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export function parseToolboxCreateArgs(args) {
|
|
54
|
+
let name = "";
|
|
55
|
+
let serviceUrl = "";
|
|
56
|
+
let description = "";
|
|
57
|
+
let businessDomain = "";
|
|
58
|
+
let pretty = true;
|
|
59
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
60
|
+
const a = args[i];
|
|
61
|
+
if (a === "--name" && args[i + 1]) {
|
|
62
|
+
name = args[++i];
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (a === "--service-url" && args[i + 1]) {
|
|
66
|
+
serviceUrl = args[++i];
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (a === "--description" && args[i + 1]) {
|
|
70
|
+
description = args[++i];
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if ((a === "-bd" || a === "--biz-domain") && args[i + 1]) {
|
|
74
|
+
businessDomain = args[++i];
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (a === "--pretty") {
|
|
78
|
+
pretty = true;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (a === "--compact") {
|
|
82
|
+
pretty = false;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (!name)
|
|
87
|
+
throw new Error("Missing required flag: --name");
|
|
88
|
+
if (!serviceUrl)
|
|
89
|
+
throw new Error("Missing required flag: --service-url");
|
|
90
|
+
if (!businessDomain)
|
|
91
|
+
businessDomain = resolveBusinessDomain();
|
|
92
|
+
return { name, serviceUrl, description, businessDomain, pretty };
|
|
93
|
+
}
|
|
94
|
+
async function runToolboxCreate(args) {
|
|
95
|
+
let opts;
|
|
96
|
+
try {
|
|
97
|
+
opts = parseToolboxCreateArgs(args);
|
|
98
|
+
}
|
|
99
|
+
catch (e) {
|
|
100
|
+
console.error(e instanceof Error ? e.message : String(e));
|
|
101
|
+
return 1;
|
|
102
|
+
}
|
|
103
|
+
const token = await ensureValidToken();
|
|
104
|
+
const body = await createToolbox({
|
|
105
|
+
baseUrl: token.baseUrl,
|
|
106
|
+
accessToken: token.accessToken,
|
|
107
|
+
name: opts.name,
|
|
108
|
+
description: opts.description,
|
|
109
|
+
serviceUrl: opts.serviceUrl,
|
|
110
|
+
businessDomain: opts.businessDomain,
|
|
111
|
+
});
|
|
112
|
+
console.log(formatCallOutput(body, opts.pretty));
|
|
113
|
+
return 0;
|
|
114
|
+
}
|
|
115
|
+
// ── list ──────────────────────────────────────────────────────────────────────
|
|
116
|
+
async function runToolboxList(args) {
|
|
117
|
+
let keyword;
|
|
118
|
+
let limit;
|
|
119
|
+
let offset;
|
|
120
|
+
let businessDomain = "";
|
|
121
|
+
let pretty = true;
|
|
122
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
123
|
+
const a = args[i];
|
|
124
|
+
if (a === "--keyword" && args[i + 1]) {
|
|
125
|
+
keyword = args[++i];
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
if (a === "--limit" && args[i + 1]) {
|
|
129
|
+
const n = parseInt(args[++i], 10);
|
|
130
|
+
if (Number.isNaN(n)) {
|
|
131
|
+
console.error("--limit must be a number");
|
|
132
|
+
return 1;
|
|
133
|
+
}
|
|
134
|
+
limit = n;
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (a === "--offset" && args[i + 1]) {
|
|
138
|
+
const n = parseInt(args[++i], 10);
|
|
139
|
+
if (Number.isNaN(n)) {
|
|
140
|
+
console.error("--offset must be a number");
|
|
141
|
+
return 1;
|
|
142
|
+
}
|
|
143
|
+
offset = n;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
if ((a === "-bd" || a === "--biz-domain") && args[i + 1]) {
|
|
147
|
+
businessDomain = args[++i];
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (a === "--pretty") {
|
|
151
|
+
pretty = true;
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
if (a === "--compact") {
|
|
155
|
+
pretty = false;
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (!businessDomain)
|
|
160
|
+
businessDomain = resolveBusinessDomain();
|
|
161
|
+
const token = await ensureValidToken();
|
|
162
|
+
const body = await listToolboxes({
|
|
163
|
+
baseUrl: token.baseUrl,
|
|
164
|
+
accessToken: token.accessToken,
|
|
165
|
+
businessDomain,
|
|
166
|
+
keyword, limit, offset,
|
|
167
|
+
});
|
|
168
|
+
console.log(formatCallOutput(body, pretty));
|
|
169
|
+
return 0;
|
|
170
|
+
}
|
|
171
|
+
export function parseToolboxSetStatusArgs(args) {
|
|
172
|
+
let boxId = "";
|
|
173
|
+
let businessDomain = "";
|
|
174
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
175
|
+
const a = args[i];
|
|
176
|
+
if ((a === "-bd" || a === "--biz-domain") && args[i + 1]) {
|
|
177
|
+
businessDomain = args[++i];
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
if (!a.startsWith("-"))
|
|
181
|
+
boxId = a;
|
|
182
|
+
}
|
|
183
|
+
if (!boxId)
|
|
184
|
+
throw new Error("Missing required argument: <box-id>");
|
|
185
|
+
if (!businessDomain)
|
|
186
|
+
businessDomain = resolveBusinessDomain();
|
|
187
|
+
return { boxId, businessDomain };
|
|
188
|
+
}
|
|
189
|
+
async function runToolboxSetStatus(args, status) {
|
|
190
|
+
let opts;
|
|
191
|
+
try {
|
|
192
|
+
opts = parseToolboxSetStatusArgs(args);
|
|
193
|
+
}
|
|
194
|
+
catch (e) {
|
|
195
|
+
console.error(`Usage: kweaver toolbox ${status === "published" ? "publish" : "unpublish"} <box-id>`);
|
|
196
|
+
return 1;
|
|
197
|
+
}
|
|
198
|
+
const token = await ensureValidToken();
|
|
199
|
+
await setToolboxStatus({
|
|
200
|
+
baseUrl: token.baseUrl,
|
|
201
|
+
accessToken: token.accessToken,
|
|
202
|
+
businessDomain: opts.businessDomain,
|
|
203
|
+
boxId: opts.boxId,
|
|
204
|
+
status,
|
|
205
|
+
});
|
|
206
|
+
console.error(`${status === "published" ? "Published" : "Unpublished"} toolbox ${opts.boxId}`);
|
|
207
|
+
return 0;
|
|
208
|
+
}
|
|
209
|
+
// ── delete ────────────────────────────────────────────────────────────────────
|
|
210
|
+
function confirmYes(prompt) {
|
|
211
|
+
return new Promise((resolve) => {
|
|
212
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
213
|
+
rl.question(`${prompt} [y/N] `, (answer) => {
|
|
214
|
+
rl.close();
|
|
215
|
+
const t = answer.trim().toLowerCase();
|
|
216
|
+
resolve(t === "y" || t === "yes");
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
async function runToolboxDelete(args) {
|
|
221
|
+
let boxId = "";
|
|
222
|
+
let yes = false;
|
|
223
|
+
let businessDomain = "";
|
|
224
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
225
|
+
const a = args[i];
|
|
226
|
+
if (a === "--yes" || a === "-y")
|
|
227
|
+
yes = true;
|
|
228
|
+
else if ((a === "-bd" || a === "--biz-domain") && args[i + 1]) {
|
|
229
|
+
businessDomain = args[++i];
|
|
230
|
+
}
|
|
231
|
+
else if (!a.startsWith("-"))
|
|
232
|
+
boxId = a;
|
|
233
|
+
}
|
|
234
|
+
if (!boxId) {
|
|
235
|
+
console.error("Usage: kweaver toolbox delete <box-id> [-y|--yes]");
|
|
236
|
+
return 1;
|
|
237
|
+
}
|
|
238
|
+
if (!yes) {
|
|
239
|
+
const ok = await confirmYes(`Delete toolbox ${boxId}?`);
|
|
240
|
+
if (!ok) {
|
|
241
|
+
console.error("Aborted.");
|
|
242
|
+
return 1;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (!businessDomain)
|
|
246
|
+
businessDomain = resolveBusinessDomain();
|
|
247
|
+
const token = await ensureValidToken();
|
|
248
|
+
await deleteToolbox({
|
|
249
|
+
baseUrl: token.baseUrl,
|
|
250
|
+
accessToken: token.accessToken,
|
|
251
|
+
businessDomain,
|
|
252
|
+
boxId,
|
|
253
|
+
});
|
|
254
|
+
console.error(`Deleted toolbox ${boxId}`);
|
|
255
|
+
return 0;
|
|
256
|
+
}
|
package/package.json
CHANGED