@thinkingai/ae-cli 1.0.20 → 1.0.22

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.
@@ -7,7 +7,7 @@ import {
7
7
  loadMcpTokenStore,
8
8
  setMcpTokenManual,
9
9
  validateMcpToken
10
- } from "./chunk-5CCFSPAF.js";
10
+ } from "./chunk-MPFTXJFG.js";
11
11
  import {
12
12
  clearToken,
13
13
  getAuthStatus,
@@ -15,7 +15,7 @@ import {
15
15
  resolveHost,
16
16
  setTokenManual,
17
17
  validateToken
18
- } from "./chunk-OVMQFFC2.js";
18
+ } from "./chunk-24ZKQWG2.js";
19
19
  import {
20
20
  loadConfig,
21
21
  saveConfig
@@ -30,6 +30,16 @@ function registerAuth(program) {
30
30
  printError("config", "No AE host configured.", "Run: ae-cli config set-host");
31
31
  process.exit(1);
32
32
  }
33
+ const config = loadConfig();
34
+ if (!config.hosts[host]) {
35
+ config.hosts[host] = { label: host };
36
+ if (!config.activeHost) {
37
+ config.activeHost = host;
38
+ }
39
+ saveConfig(config);
40
+ process.stderr.write(`[ae-cli] Config saved for ${host}
41
+ `);
42
+ }
33
43
  try {
34
44
  const token = await getToken(host);
35
45
  process.stderr.write(`[ae-cli] Authenticated to ${host}
@@ -7,7 +7,7 @@ import {
7
7
  saveToken,
8
8
  setTokenManual,
9
9
  validateToken
10
- } from "./chunk-OVMQFFC2.js";
10
+ } from "./chunk-24ZKQWG2.js";
11
11
  import "./chunk-TMMUBSKW.js";
12
12
  export {
13
13
  clearToken,
@@ -140,6 +140,37 @@ function extractTokenViaOsascript(hostUrl) {
140
140
  return { token: null, error: "no_tab" };
141
141
  }
142
142
  }
143
+ function extractTokenFromAllTabs() {
144
+ const lines = [
145
+ 'tell application "Google Chrome"',
146
+ " repeat with w in windows",
147
+ " repeat with t in tabs of w",
148
+ " try",
149
+ ` set tokenVal to execute t javascript "localStorage.getItem('ACCESS_TOKEN')"`,
150
+ ' if tokenVal is not null and tokenVal is not missing value and tokenVal is not "" then',
151
+ " return tokenVal",
152
+ " end if",
153
+ " end try",
154
+ " end repeat",
155
+ " end repeat",
156
+ ' return "NO_TOKEN_FOUND"',
157
+ "end tell"
158
+ ];
159
+ try {
160
+ const args = lines.flatMap((line) => ["-e", line]);
161
+ const result = execFileSync("osascript", args, { encoding: "utf8", timeout: 1e4 }).trim();
162
+ if (result === "NO_TOKEN_FOUND" || !result || result === "missing value") {
163
+ return { token: null, error: "no_token" };
164
+ }
165
+ return { token: result.replace(/^["']|["']$/g, ""), error: null };
166
+ } catch (e) {
167
+ const msg = e.message || "";
168
+ if (msg.includes("not allowed") || msg.includes("assistive access") || msg.includes("(-1743)")) {
169
+ return { token: null, error: "no_js_permission" };
170
+ }
171
+ return { token: null, error: "no_tab" };
172
+ }
173
+ }
143
174
  async function requestTokenViaOsascript(hostUrl) {
144
175
  process.stderr.write(`[ae-cli] No AE tab found in Chrome. Opening ${hostUrl} ...
145
176
  `);
@@ -164,13 +195,17 @@ async function requestTokenViaOsascript(hostUrl) {
164
195
  const deadline = Date.now() + OSASCRIPT_POLL_TIMEOUT_MS;
165
196
  while (Date.now() < deadline) {
166
197
  await new Promise((r) => setTimeout(r, OSASCRIPT_POLL_INTERVAL_MS));
167
- const { token, error } = extractTokenViaOsascript(hostUrl);
168
- if (token) {
198
+ let result = extractTokenViaOsascript(hostUrl);
199
+ if (result.error === "no_tab") {
200
+ const fallback = extractTokenFromAllTabs();
201
+ if (fallback.token) result = fallback;
202
+ }
203
+ if (result.token) {
169
204
  process.stderr.write(`[ae-cli] Token captured from Chrome for ${hostUrl}.
170
205
  `);
171
- return token;
206
+ return result.token;
172
207
  }
173
- if (error === "no_js_permission") return null;
208
+ if (result.error === "no_js_permission") return null;
174
209
  }
175
210
  process.stderr.write(`[ae-cli] Polling timed out after ${OSASCRIPT_POLL_TIMEOUT_MS / 1e3}s.
176
211
  `);
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getToken
3
- } from "./chunk-OVMQFFC2.js";
3
+ } from "./chunk-24ZKQWG2.js";
4
4
  import {
5
5
  forceMigrateFromFallback,
6
6
  getActiveHost,
@@ -2,7 +2,7 @@ import {
2
2
  clearToken,
3
3
  getToken,
4
4
  resolveHost
5
- } from "./chunk-OVMQFFC2.js";
5
+ } from "./chunk-24ZKQWG2.js";
6
6
  import {
7
7
  safeJsonParse
8
8
  } from "./chunk-TMMUBSKW.js";
@@ -59,6 +59,34 @@ async function httpGet(modulePath, params = {}, hostUrl) {
59
59
  async function httpPost(modulePath, params = {}, body, hostUrl) {
60
60
  return request("POST", modulePath, params, body ?? {}, true, hostUrl);
61
61
  }
62
+ async function httpDelete(modulePath, params = {}, body, hostUrl) {
63
+ return request("DELETE", modulePath, params, body ?? null, true, hostUrl);
64
+ }
65
+ async function uploadRequest(modulePath, form, params = {}, retry = true, hostUrl) {
66
+ const resolvedHost = resolveHost(hostUrl);
67
+ const token = await getToken(resolvedHost);
68
+ const url = buildUrl(resolvedHost, modulePath, params);
69
+ const headers = {
70
+ "Authorization": `bearer ${token}`
71
+ };
72
+ const resp = await fetch(url, { method: "POST", headers, body: form });
73
+ if ((resp.status === 401 || resp.status === 403) && retry) {
74
+ clearToken(resolvedHost);
75
+ return uploadRequest(modulePath, form, params, false, resolvedHost);
76
+ }
77
+ const data = safeJsonParse(await resp.text());
78
+ if (data.return_code === -1001 && retry) {
79
+ clearToken(resolvedHost);
80
+ return uploadRequest(modulePath, form, params, false, resolvedHost);
81
+ }
82
+ if (data.return_code !== 0 && data.return_code !== void 0) {
83
+ throw new Error(`AE API error: ${data.return_message || "unknown"} (code: ${data.return_code})`);
84
+ }
85
+ return data.data !== void 0 ? data.data : data;
86
+ }
87
+ async function httpUpload(modulePath, form, params = {}, hostUrl) {
88
+ return uploadRequest(modulePath, form, params, true, hostUrl);
89
+ }
62
90
  async function wsQueryOnce(projectId, requestId, qp, eventModel, options = {}, token, hostUrl, timeoutMs = 3e4) {
63
91
  const wsUrl = buildWsUrl(hostUrl, token);
64
92
  return new Promise((resolve, reject) => {
@@ -142,6 +170,8 @@ async function queryReportData(projectId, reportId, qp, eventModel, options = {}
142
170
  export {
143
171
  httpGet,
144
172
  httpPost,
173
+ httpDelete,
174
+ httpUpload,
145
175
  wsQuery,
146
176
  querySql,
147
177
  queryReportData
@@ -1,15 +1,19 @@
1
1
  import {
2
+ httpDelete,
2
3
  httpGet,
3
4
  httpPost,
5
+ httpUpload,
4
6
  queryReportData,
5
7
  querySql,
6
8
  wsQuery
7
- } from "./chunk-TOXRLDUP.js";
8
- import "./chunk-OVMQFFC2.js";
9
+ } from "./chunk-NBFTPIAH.js";
10
+ import "./chunk-24ZKQWG2.js";
9
11
  import "./chunk-TMMUBSKW.js";
10
12
  export {
13
+ httpDelete,
11
14
  httpGet,
12
15
  httpPost,
16
+ httpUpload,
13
17
  queryReportData,
14
18
  querySql,
15
19
  wsQuery
@@ -4,7 +4,7 @@ import {
4
4
  getToken,
5
5
  loadToken,
6
6
  validateToken
7
- } from "./chunk-OVMQFFC2.js";
7
+ } from "./chunk-24ZKQWG2.js";
8
8
  import {
9
9
  addHost,
10
10
  listHosts,
package/dist/index.js CHANGED
@@ -62,7 +62,7 @@ function createRuntimeContext(cmd, opts, globalOpts) {
62
62
  let _clientModule = null;
63
63
  async function getClient() {
64
64
  if (!_clientModule) {
65
- _clientModule = await import("./client-FPA76DGY.js");
65
+ _clientModule = await import("./client-7S23DVHH.js");
66
66
  }
67
67
  return _clientModule;
68
68
  }
@@ -105,7 +105,7 @@ function createRuntimeContext(cmd, opts, globalOpts) {
105
105
  return client.queryReportData(projectId, reportId, qp, eventModel, options, ctx.host());
106
106
  },
107
107
  async token() {
108
- const { getToken } = await import("./auth-T3ILGJKW.js");
108
+ const { getToken } = await import("./auth-YM7OI23X.js");
109
109
  return getToken(ctx.host());
110
110
  },
111
111
  host() {
@@ -210,42 +210,42 @@ program.name("ae-cli").version(version).description("CLI tool for ThinkingAI (AE
210
210
  async function loadCommands() {
211
211
  const commands = [];
212
212
  try {
213
- const teAnalysis = await import("./te-analysis-CFQBXUCO.js");
213
+ const teAnalysis = await import("./te-analysis-RQST6AT3.js");
214
214
  commands.push(...teAnalysis.default);
215
215
  } catch {
216
216
  }
217
217
  try {
218
- const teAudience = await import("./te-audience-WPBBWADL.js");
218
+ const teAudience = await import("./te-audience-TJ74UJI3.js");
219
219
  commands.push(...teAudience.default);
220
220
  } catch {
221
221
  }
222
222
  try {
223
- const teMeta = await import("./te-meta-BO45GW32.js");
223
+ const teMeta = await import("./te-meta-25SLZFXJ.js");
224
224
  commands.push(...teMeta.default);
225
225
  } catch {
226
226
  }
227
227
  try {
228
- const teCommon = await import("./te-common-GL3KBZPD.js");
228
+ const teCommon = await import("./te-common-W5URM2SH.js");
229
229
  commands.push(...teCommon.default);
230
230
  } catch {
231
231
  }
232
232
  try {
233
- const engage = await import("./te-engage-2VFM37ZM.js");
233
+ const engage = await import("./te-engage-57UKFV74.js");
234
234
  commands.push(...engage.default);
235
235
  } catch {
236
236
  }
237
237
  try {
238
- const community = await import("./te-community-3XEJNSQL.js");
238
+ const community = await import("./te-community-YRV2VAD4.js");
239
239
  commands.push(...community.default);
240
240
  } catch {
241
241
  }
242
242
  try {
243
- const dataops = await import("./te-dataops-H4WSMCG5.js");
243
+ const dataops = await import("./te-dataops-ZPH72BCK.js");
244
244
  commands.push(...dataops.default);
245
245
  } catch {
246
246
  }
247
247
  try {
248
- const teKb = await import("./te-kb-U6SQUJVC.js");
248
+ const teKb = await import("./te-kb-GD7SJRYB.js");
249
249
  commands.push(...teKb.default);
250
250
  } catch {
251
251
  }
@@ -253,21 +253,21 @@ async function loadCommands() {
253
253
  }
254
254
  async function registerAuthCommands() {
255
255
  try {
256
- const { registerAuth } = await import("./auth-A4NV2VHD.js");
256
+ const { registerAuth } = await import("./auth-5S7SPPEJ.js");
257
257
  registerAuth(program);
258
258
  } catch {
259
259
  }
260
260
  }
261
261
  async function registerConfigCommands() {
262
262
  try {
263
- const { registerConfig } = await import("./config-QZIEYXQZ.js");
263
+ const { registerConfig } = await import("./config-RVUESJRF.js");
264
264
  registerConfig(program);
265
265
  } catch {
266
266
  }
267
267
  }
268
268
  async function registerApiCommand() {
269
269
  try {
270
- const { registerApi } = await import("./raw-MZIKHQH4.js");
270
+ const { registerApi } = await import("./raw-5SYAUCJQ.js");
271
271
  registerApi(program);
272
272
  } catch {
273
273
  }
@@ -5,10 +5,10 @@ import {
5
5
  import {
6
6
  httpGet,
7
7
  httpPost
8
- } from "./chunk-TOXRLDUP.js";
8
+ } from "./chunk-NBFTPIAH.js";
9
9
  import {
10
10
  resolveHost
11
- } from "./chunk-OVMQFFC2.js";
11
+ } from "./chunk-24ZKQWG2.js";
12
12
  import {
13
13
  safeJsonParse
14
14
  } from "./chunk-TMMUBSKW.js";
@@ -2,8 +2,8 @@ import {
2
2
  callMcpTool,
3
3
  parseMcpResult,
4
4
  resolveMcpUrl
5
- } from "./chunk-5CCFSPAF.js";
6
- import "./chunk-OVMQFFC2.js";
5
+ } from "./chunk-MPFTXJFG.js";
6
+ import "./chunk-24ZKQWG2.js";
7
7
  import "./chunk-TMMUBSKW.js";
8
8
 
9
9
  // src/commands/te-analysis/shared.ts
@@ -2,8 +2,8 @@ import {
2
2
  callMcpTool,
3
3
  parseMcpResult,
4
4
  resolveMcpUrl
5
- } from "./chunk-5CCFSPAF.js";
6
- import "./chunk-OVMQFFC2.js";
5
+ } from "./chunk-MPFTXJFG.js";
6
+ import "./chunk-24ZKQWG2.js";
7
7
  import "./chunk-TMMUBSKW.js";
8
8
 
9
9
  // src/commands/te-audience/shared.ts
@@ -2,8 +2,8 @@ import {
2
2
  callMcpTool,
3
3
  parseMcpResult,
4
4
  resolveMcpUrl
5
- } from "./chunk-5CCFSPAF.js";
6
- import "./chunk-OVMQFFC2.js";
5
+ } from "./chunk-MPFTXJFG.js";
6
+ import "./chunk-24ZKQWG2.js";
7
7
  import "./chunk-TMMUBSKW.js";
8
8
 
9
9
  // src/commands/te-common/shared.ts
@@ -3,8 +3,8 @@ import {
3
3
  parseMcpResult,
4
4
  registerMcpMappings,
5
5
  resolveMcpUrl
6
- } from "./chunk-5CCFSPAF.js";
7
- import "./chunk-OVMQFFC2.js";
6
+ } from "./chunk-MPFTXJFG.js";
7
+ import "./chunk-24ZKQWG2.js";
8
8
  import "./chunk-TMMUBSKW.js";
9
9
 
10
10
  // src/commands/te-community/get_channel_info.ts
@@ -3,8 +3,8 @@ import {
3
3
  parseMcpResult,
4
4
  registerMcpMappings,
5
5
  resolveMcpUrl
6
- } from "./chunk-5CCFSPAF.js";
7
- import "./chunk-OVMQFFC2.js";
6
+ } from "./chunk-MPFTXJFG.js";
7
+ import "./chunk-24ZKQWG2.js";
8
8
  import "./chunk-TMMUBSKW.js";
9
9
 
10
10
  // src/commands/te-dataops/datatable/list-tables-by-page.ts
@@ -3,8 +3,8 @@ import {
3
3
  parseMcpResult,
4
4
  registerMcpMappings,
5
5
  resolveMcpUrl
6
- } from "./chunk-5CCFSPAF.js";
7
- import "./chunk-OVMQFFC2.js";
6
+ } from "./chunk-MPFTXJFG.js";
7
+ import "./chunk-24ZKQWG2.js";
8
8
  import "./chunk-TMMUBSKW.js";
9
9
 
10
10
  // src/commands/te-engage/utils.ts
@@ -0,0 +1,407 @@
1
+ import {
2
+ httpDelete,
3
+ httpUpload
4
+ } from "./chunk-NBFTPIAH.js";
5
+ import "./chunk-24ZKQWG2.js";
6
+ import "./chunk-TMMUBSKW.js";
7
+
8
+ // src/commands/te-kb/query.ts
9
+ var API_PATH = "/agent/api/external/knowledge-bases/query";
10
+ function buildBody(ctx) {
11
+ const body = {
12
+ query: ctx.str("query"),
13
+ sources: ctx.json("sources")
14
+ };
15
+ const modelId = ctx.str("model-id");
16
+ if (modelId) body.modelId = modelId;
17
+ const maxTurnsRaw = ctx.str("max-turns");
18
+ if (maxTurnsRaw !== "") body.maxTurns = ctx.num("max-turns");
19
+ return body;
20
+ }
21
+ var query = {
22
+ service: "kb",
23
+ command: "+query",
24
+ description: "Query knowledge.",
25
+ flags: [
26
+ { name: "query", type: "string", required: true, alias: "q", desc: "Natural language question to query against the knowledge bases" },
27
+ { name: "sources", type: "json", required: true, desc: 'JSON array of knowledge base refs, e.g. [{"scope":"company","name":"engineering-handbook"}]' },
28
+ { name: "model-id", type: "string", required: false, default: "AE-Auto", desc: "Model identifier (default: AE-Auto)" },
29
+ { name: "max-turns", type: "number", required: false, default: 6, desc: "Maximum reasoning turns (default: 6)" }
30
+ ],
31
+ risk: "read",
32
+ dryRun: (ctx) => ({
33
+ method: "POST",
34
+ url: `${ctx.host().replace(/\/$/, "")}${API_PATH}`,
35
+ body: buildBody(ctx)
36
+ }),
37
+ execute: async (ctx) => ctx.api("POST", API_PATH, {}, buildBody(ctx))
38
+ };
39
+
40
+ // src/commands/te-kb/add.ts
41
+ import { promises as fs } from "fs";
42
+ import * as path from "path";
43
+ import TurndownService from "turndown";
44
+ var API_PATH2 = "/agent/api/external/knowledge-bases/sources/upload";
45
+ var MD_EXT = /* @__PURE__ */ new Set([".md", ".markdown"]);
46
+ function normalizeFilesInput(raw) {
47
+ if (!Array.isArray(raw)) {
48
+ throw new Error(`--files must be a JSON array of strings, e.g. '["./a.md","./docs","https://example.com/page"]'`);
49
+ }
50
+ const items = [];
51
+ for (const v of raw) {
52
+ if (typeof v !== "string") {
53
+ throw new Error(`--files entries must be strings (got: ${JSON.stringify(v)})`);
54
+ }
55
+ const trimmed = v.trim();
56
+ if (trimmed) items.push(trimmed);
57
+ }
58
+ return items;
59
+ }
60
+ function isUrl(s) {
61
+ return /^https?:\/\//i.test(s);
62
+ }
63
+ function classifyInput(item) {
64
+ return isUrl(item) ? "url" : "path";
65
+ }
66
+ function sanitizeFilename(name) {
67
+ const cleaned = name.replace(/[\\/:*?"<>|\s]+/g, "-").replace(/^-+|-+$/g, "");
68
+ return cleaned || "document";
69
+ }
70
+ async function readLocalFile(filePath) {
71
+ const ext = path.extname(filePath).toLowerCase();
72
+ if (!MD_EXT.has(ext)) {
73
+ throw new Error(`Not a markdown file (only .md / .markdown allowed): ${filePath}`);
74
+ }
75
+ const content = await fs.readFile(filePath, "utf8");
76
+ return { filename: path.basename(filePath), content, origin: "file", source: filePath };
77
+ }
78
+ async function readDirectory(dir) {
79
+ const entries = await fs.readdir(dir, { withFileTypes: true });
80
+ const files = [];
81
+ for (const entry of entries) {
82
+ if (!entry.isFile()) continue;
83
+ const ext = path.extname(entry.name).toLowerCase();
84
+ if (!MD_EXT.has(ext)) continue;
85
+ const full = path.join(dir, entry.name);
86
+ const content = await fs.readFile(full, "utf8");
87
+ files.push({ filename: entry.name, content, origin: "dir", source: full });
88
+ }
89
+ if (files.length === 0) {
90
+ throw new Error(`No .md / .markdown files found in directory: ${dir}`);
91
+ }
92
+ return files;
93
+ }
94
+ function deriveFilenameFromUrl(rawUrl) {
95
+ try {
96
+ const u = new URL(rawUrl);
97
+ const lastSeg = u.pathname.split("/").filter(Boolean).pop();
98
+ const base = lastSeg ? lastSeg.replace(/\.[^.]+$/, "") : u.hostname;
99
+ return `${sanitizeFilename(base)}.md`;
100
+ } catch {
101
+ return `${sanitizeFilename(rawUrl)}.md`;
102
+ }
103
+ }
104
+ async function fetchAsMarkdown(rawUrl) {
105
+ const resp = await fetch(rawUrl);
106
+ if (!resp.ok) {
107
+ throw new Error(`Failed to fetch ${rawUrl}: HTTP ${resp.status}`);
108
+ }
109
+ const html = await resp.text();
110
+ const turndown = new TurndownService({ headingStyle: "atx", codeBlockStyle: "fenced" });
111
+ const markdown = turndown.turndown(html);
112
+ return {
113
+ filename: deriveFilenameFromUrl(rawUrl),
114
+ content: markdown,
115
+ origin: "url",
116
+ source: rawUrl
117
+ };
118
+ }
119
+ async function resolveLocalPath(p) {
120
+ const abs = path.resolve(p);
121
+ let stat;
122
+ try {
123
+ stat = await fs.stat(abs);
124
+ } catch {
125
+ throw new Error(`Path not found: ${p}`);
126
+ }
127
+ if (stat.isDirectory()) {
128
+ return readDirectory(abs);
129
+ }
130
+ if (stat.isFile()) {
131
+ return [await readLocalFile(abs)];
132
+ }
133
+ throw new Error(`Unsupported path (not file or directory): ${p}`);
134
+ }
135
+ async function collectFiles(ctx) {
136
+ const items = normalizeFilesInput(ctx.json("files"));
137
+ if (items.length === 0) {
138
+ throw new Error("--files must contain at least one entry");
139
+ }
140
+ const collected = [];
141
+ for (const item of items) {
142
+ if (classifyInput(item) === "url") {
143
+ collected.push(await fetchAsMarkdown(item));
144
+ } else {
145
+ collected.push(...await resolveLocalPath(item));
146
+ }
147
+ }
148
+ if (collected.length === 0) {
149
+ throw new Error("No markdown files collected from the given inputs");
150
+ }
151
+ return dedupeByFilename(collected);
152
+ }
153
+ function dedupeByFilename(files) {
154
+ const used = /* @__PURE__ */ new Map();
155
+ return files.map((f) => {
156
+ const count = used.get(f.filename) ?? 0;
157
+ used.set(f.filename, count + 1);
158
+ if (count === 0) return f;
159
+ const ext = path.extname(f.filename);
160
+ const stem = f.filename.slice(0, f.filename.length - ext.length);
161
+ return { ...f, filename: `${stem}-${count}${ext}` };
162
+ });
163
+ }
164
+ function buildForm(name, files) {
165
+ const form = new FormData();
166
+ form.append("name", name);
167
+ for (const f of files) {
168
+ form.append("files", new Blob([f.content], { type: "text/markdown" }), f.filename);
169
+ }
170
+ return form;
171
+ }
172
+ var add = {
173
+ service: "kb",
174
+ command: "+add",
175
+ description: "Upload markdown sources to a knowledge. --files accepts a JSON array; each entry can be a .md/.markdown file path, a directory path (all .md/.markdown inside, non-recursive), or an http(s) URL (HTML auto-converted to markdown).",
176
+ flags: [
177
+ { name: "name", type: "string", required: true, desc: "Knowledge base name" },
178
+ {
179
+ name: "files",
180
+ type: "json",
181
+ required: true,
182
+ desc: `JSON array of strings. Each entry can be a .md/.markdown file path, a directory path, or an http(s) URL. Example: '["./a.md","./docs","https://example.com/page"]'`
183
+ }
184
+ ],
185
+ risk: "write",
186
+ validate: (ctx) => {
187
+ normalizeFilesInput(ctx.json("files"));
188
+ },
189
+ dryRun: (ctx) => {
190
+ const items = normalizeFilesInput(ctx.json("files"));
191
+ return {
192
+ method: "POST",
193
+ url: `${ctx.host().replace(/\/$/, "")}${API_PATH2}`,
194
+ body: {
195
+ name: ctx.str("name"),
196
+ files: items.map((item) => ({ value: item, type: classifyInput(item) })),
197
+ contentType: "multipart/form-data"
198
+ }
199
+ };
200
+ },
201
+ execute: async (ctx) => {
202
+ const name = ctx.str("name");
203
+ const files = await collectFiles(ctx);
204
+ const form = buildForm(name, files);
205
+ const result = await httpUpload(API_PATH2, form, {}, ctx.host());
206
+ return {
207
+ uploaded: files.map((f) => ({ filename: f.filename, origin: f.origin, source: f.source })),
208
+ result
209
+ };
210
+ }
211
+ };
212
+
213
+ // src/commands/te-kb/compile.ts
214
+ var API_PATH3 = "/agent/api/external/knowledge-bases/compile";
215
+ var VALID_MODES = /* @__PURE__ */ new Set(["incremental", "full"]);
216
+ function getMode(ctx) {
217
+ const mode = ctx.str("mode") || "incremental";
218
+ if (!VALID_MODES.has(mode)) {
219
+ throw new Error(`Invalid --mode: ${mode}. Must be one of: incremental | full`);
220
+ }
221
+ return mode;
222
+ }
223
+ function buildBody2(ctx) {
224
+ return {
225
+ name: ctx.str("name"),
226
+ mode: getMode(ctx)
227
+ };
228
+ }
229
+ var compile = {
230
+ service: "kb",
231
+ command: "+compile",
232
+ description: "Compile a knowledge.",
233
+ flags: [
234
+ { name: "name", type: "string", required: true, desc: "Knowledge base name" },
235
+ { name: "mode", type: "string", required: false, default: "incremental", desc: "Compile mode: incremental | full (default: incremental)" }
236
+ ],
237
+ risk: "write",
238
+ validate: (ctx) => {
239
+ getMode(ctx);
240
+ },
241
+ dryRun: (ctx) => ({
242
+ method: "POST",
243
+ url: `${ctx.host().replace(/\/$/, "")}${API_PATH3}`,
244
+ body: buildBody2(ctx)
245
+ }),
246
+ execute: async (ctx) => ctx.api("POST", API_PATH3, {}, buildBody2(ctx))
247
+ };
248
+
249
+ // src/commands/te-kb/remove.ts
250
+ var API_PATH4 = "/agent/api/external/knowledge-bases";
251
+ function buildBody3(ctx) {
252
+ return { name: ctx.str("name") };
253
+ }
254
+ var remove = {
255
+ service: "kb",
256
+ command: "+remove",
257
+ description: "Delete an entire knowledge.",
258
+ flags: [
259
+ { name: "name", type: "string", required: true, desc: "Knowledge base name to delete" }
260
+ ],
261
+ risk: "write",
262
+ dryRun: (ctx) => ({
263
+ method: "DELETE",
264
+ url: `${ctx.host().replace(/\/$/, "")}${API_PATH4}`,
265
+ body: buildBody3(ctx)
266
+ }),
267
+ execute: async (ctx) => httpDelete(API_PATH4, {}, buildBody3(ctx), ctx.host())
268
+ };
269
+
270
+ // src/commands/te-kb/create.ts
271
+ var API_PATH5 = "/agent/api/external/knowledge-bases/create";
272
+ var VALID_SCOPES = /* @__PURE__ */ new Set(["personal", "company"]);
273
+ function validateScope(scope) {
274
+ if (!VALID_SCOPES.has(scope)) {
275
+ throw new Error(`Invalid --scope: ${scope}. Must be one of: personal | company`);
276
+ }
277
+ }
278
+ function normalizeTags(raw) {
279
+ if (raw === void 0 || raw === null) return void 0;
280
+ if (!Array.isArray(raw)) {
281
+ throw new Error(`--tags must be a JSON array of strings, e.g. '["t1","t2"]'`);
282
+ }
283
+ const tags = [];
284
+ for (const v of raw) {
285
+ if (typeof v !== "string") {
286
+ throw new Error(`--tags entries must be strings (got: ${JSON.stringify(v)})`);
287
+ }
288
+ const t = v.trim();
289
+ if (t) tags.push(t);
290
+ }
291
+ return tags;
292
+ }
293
+ function buildBody4(ctx) {
294
+ const body = {
295
+ scope: ctx.str("scope"),
296
+ name: ctx.str("name")
297
+ };
298
+ const description = ctx.str("description");
299
+ if (description) body.description = description;
300
+ const tags = normalizeTags(ctx.json("tags"));
301
+ if (tags && tags.length > 0) body.tags = tags;
302
+ const projectId = ctx.str("project-id");
303
+ if (projectId) body.projectId = projectId;
304
+ const projectName = ctx.str("project-name");
305
+ if (projectName) body.projectName = projectName;
306
+ return body;
307
+ }
308
+ var create = {
309
+ service: "kb",
310
+ command: "+new",
311
+ description: "Create a new knowledge.",
312
+ flags: [
313
+ { name: "scope", type: "string", required: true, desc: "Knowledge base scope: personal | company" },
314
+ { name: "name", type: "string", required: true, desc: "Knowledge base name (\u226430 chars, unique per scope)" },
315
+ { name: "description", type: "string", required: false, desc: "Optional description (\u2264200 chars)" },
316
+ { name: "tags", type: "json", required: false, desc: `Optional JSON array of tags (max 2, each \u226415 chars). Example: '["t1","t2"]'` },
317
+ { name: "project-id", type: "string", required: false, desc: "Optional project ID to bind" },
318
+ { name: "project-name", type: "string", required: false, desc: "Optional project display name" }
319
+ ],
320
+ risk: "write",
321
+ validate: (ctx) => {
322
+ validateScope(ctx.str("scope"));
323
+ normalizeTags(ctx.json("tags"));
324
+ },
325
+ dryRun: (ctx) => ({
326
+ method: "POST",
327
+ url: `${ctx.host().replace(/\/$/, "")}${API_PATH5}`,
328
+ body: buildBody4(ctx)
329
+ }),
330
+ execute: async (ctx) => ctx.api("POST", API_PATH5, {}, buildBody4(ctx))
331
+ };
332
+
333
+ // src/commands/te-kb/rm-source.ts
334
+ var API_PATH6 = "/agent/api/external/knowledge-bases/sources";
335
+ function buildBody5(ctx) {
336
+ return {
337
+ name: ctx.str("name"),
338
+ displayName: ctx.str("display-name")
339
+ };
340
+ }
341
+ var rmSource = {
342
+ service: "kb",
343
+ command: "+rm-source",
344
+ description: "Delete a single source file inside a knowledge.",
345
+ flags: [
346
+ { name: "name", type: "string", required: true, desc: "Knowledge base name (looked up personal \u2192 company)" },
347
+ { name: "display-name", type: "string", required: true, desc: "Source file display name as uploaded (e.g. kb-1780046712-foo.md)" }
348
+ ],
349
+ risk: "write",
350
+ dryRun: (ctx) => ({
351
+ method: "DELETE",
352
+ url: `${ctx.host().replace(/\/$/, "")}${API_PATH6}`,
353
+ body: buildBody5(ctx)
354
+ }),
355
+ execute: async (ctx) => httpDelete(API_PATH6, {}, buildBody5(ctx), ctx.host())
356
+ };
357
+
358
+ // src/commands/te-kb/schema.ts
359
+ var API_PATH7 = "/agent/api/external/knowledge-bases/schema";
360
+ function buildBody6(ctx) {
361
+ const body = {
362
+ name: ctx.str("name")
363
+ };
364
+ if (ctx.bool("force")) body.force = true;
365
+ const model = ctx.str("model");
366
+ if (model) body.model = model;
367
+ return body;
368
+ }
369
+ var schema = {
370
+ service: "kb",
371
+ command: "+schema",
372
+ description: "Generate the compile schema for a knowledge base via POST /agent/api/external/knowledge-bases/schema.",
373
+ flags: [
374
+ { name: "name", type: "string", required: true, desc: "Knowledge base name (looked up personal \u2192 company)" },
375
+ { name: "force", type: "boolean", required: false, desc: "Preempt generation even when status is `generating` (use only for stuck recovery)" },
376
+ { name: "model", type: "string", required: false, desc: "Optional model displayName to use for schema generation" }
377
+ ],
378
+ risk: "write",
379
+ dryRun: (ctx) => ({
380
+ method: "POST",
381
+ url: `${ctx.host().replace(/\/$/, "")}${API_PATH7}`,
382
+ body: buildBody6(ctx)
383
+ }),
384
+ execute: async (ctx) => ctx.api("POST", API_PATH7, {}, buildBody6(ctx))
385
+ };
386
+
387
+ // src/commands/te-kb/index.ts
388
+ var commands = [
389
+ query,
390
+ add,
391
+ compile,
392
+ remove,
393
+ create,
394
+ rmSource,
395
+ schema
396
+ ];
397
+ var te_kb_default = commands;
398
+ export {
399
+ add,
400
+ compile,
401
+ create,
402
+ te_kb_default as default,
403
+ query,
404
+ remove,
405
+ rmSource,
406
+ schema
407
+ };
@@ -2,8 +2,8 @@ import {
2
2
  callMcpTool,
3
3
  parseMcpResult,
4
4
  resolveMcpUrl
5
- } from "./chunk-5CCFSPAF.js";
6
- import "./chunk-OVMQFFC2.js";
5
+ } from "./chunk-MPFTXJFG.js";
6
+ import "./chunk-24ZKQWG2.js";
7
7
  import "./chunk-TMMUBSKW.js";
8
8
 
9
9
  // src/commands/te-meta/shared.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thinkingai/ae-cli",
3
- "version": "1.0.20",
3
+ "version": "1.0.22",
4
4
  "description": "CLI tool for ThinkingAI (AE) analytics platform",
5
5
  "type": "module",
6
6
  "bin": {
@@ -44,10 +44,12 @@
44
44
  "cli-table3": "^0.6.5",
45
45
  "commander": "^12.1.0",
46
46
  "json-bigint": "^1.0.0",
47
+ "turndown": "^7.2.4",
47
48
  "ws": "^8.18.0"
48
49
  },
49
50
  "devDependencies": {
50
51
  "@types/node": "^22.0.0",
52
+ "@types/turndown": "^5.0.6",
51
53
  "@types/ws": "^8.5.0",
52
54
  "tsup": "^8.0.0",
53
55
  "tsx": "^4.0.0",
@@ -1,41 +0,0 @@
1
- // src/commands/te-kb/query.ts
2
- var API_PATH = "/api/external/knowledge-bases/query";
3
- function buildBody(ctx) {
4
- const body = {
5
- query: ctx.str("query"),
6
- sources: ctx.json("sources")
7
- };
8
- const modelId = ctx.str("model-id");
9
- if (modelId) body.modelId = modelId;
10
- const maxTurnsRaw = ctx.str("max-turns");
11
- if (maxTurnsRaw !== "") body.maxTurns = ctx.num("max-turns");
12
- return body;
13
- }
14
- var query = {
15
- service: "kb",
16
- command: "+query",
17
- description: "Query knowledge bases via /api/external/knowledge-bases/query.",
18
- flags: [
19
- { name: "query", type: "string", required: true, alias: "q", desc: "Natural language question to query against the knowledge bases" },
20
- { name: "sources", type: "json", required: true, desc: 'JSON array of knowledge base refs, e.g. [{"scope":"company","name":"engineering-handbook"}]' },
21
- { name: "model-id", type: "string", required: false, default: "AE-Auto", desc: "Model identifier (default: AE-Auto)" },
22
- { name: "max-turns", type: "number", required: false, default: 6, desc: "Maximum reasoning turns (default: 6)" }
23
- ],
24
- risk: "read",
25
- dryRun: (ctx) => ({
26
- method: "POST",
27
- url: `${ctx.host().replace(/\/$/, "")}${API_PATH}`,
28
- body: buildBody(ctx)
29
- }),
30
- execute: async (ctx) => ctx.api("POST", API_PATH, {}, buildBody(ctx))
31
- };
32
-
33
- // src/commands/te-kb/index.ts
34
- var commands = [
35
- query
36
- ];
37
- var te_kb_default = commands;
38
- export {
39
- te_kb_default as default,
40
- query
41
- };