@puyinkai/xiaobao-cli 0.1.10 → 0.2.1
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 +18 -8
- package/dist/{api-fsHHWWa3.mjs → api-DtFEKH3I.mjs} +2 -2
- package/dist/{audio-CRSMqaKo.mjs → audio-DhEiStuy.mjs} +2 -2
- package/dist/{auth-B4Yeoxae.mjs → auth-BYWDBat3.mjs} +3 -3
- package/dist/cli.mjs +15 -13
- package/dist/{consultant-E33hTGUO.mjs → consultant-DvH6ezCT.mjs} +1 -1
- package/dist/{current-CfDExInT.mjs → current-gZDEGEmi.mjs} +2 -2
- package/dist/{customer-DcQ83oKD.mjs → customer-BtAtJyM8.mjs} +1 -1
- package/dist/doc--iAF-laM.mjs +47 -0
- package/dist/doc-content-CqDVEgwX.mjs +59 -0
- package/dist/docs-C_sC8m3F.mjs +46 -0
- package/dist/{focus-XMRxnHPw.mjs → focus-BmLvFWII.mjs} +1 -1
- package/dist/{format-yjmxrbNm.mjs → format-CvKe7-yU.mjs} +6 -6
- package/dist/kb-B9IY8-fu.mjs +16 -0
- package/dist/{list-CnlQdzPp.mjs → list-CZVU6EVq.mjs} +2 -2
- package/dist/{list-dm9YaCG1.mjs → list-CiBpxZFs.mjs} +2 -2
- package/dist/{list-DFdDcHFq.mjs → list-DDGGG2p2.mjs} +2 -2
- package/dist/{list-B3nN4pd2.mjs → list-DW4Sk-76.mjs} +2 -2
- package/dist/{list-CXquxzex.mjs → list-DbReQZE2.mjs} +2 -2
- package/dist/{list-Cc4zcaNz.mjs → list-DmBz_8dR.mjs} +2 -2
- package/dist/{list-CrMOrnS-.mjs → list-VJImXOzy.mjs} +2 -2
- package/dist/{login-EtQi30zd.mjs → login-B5e9tJbS.mjs} +2 -2
- package/dist/{logout-DP7REhCd.mjs → logout-Dz_FFIRP.mjs} +2 -2
- package/dist/{project-BD0g4oAW.mjs → project-C2fvEuDl.mjs} +3 -3
- package/dist/{qa-CdMcxCE_.mjs → qa-C2TSTS-m.mjs} +6 -2
- package/dist/{resistance-6_V6At3T.mjs → resistance-BxOZNWbb.mjs} +1 -1
- package/dist/search-CBWh8yKE.mjs +75 -0
- package/dist/summary-CAm-WDNF.mjs +84 -0
- package/dist/{text-C3Ap6L5n.mjs → text-bgoI1KC-.mjs} +2 -2
- package/dist/{use-BZES4FZC.mjs → use-xbTXVwXb.mjs} +2 -2
- package/dist/visit-LX3B_OgE.mjs +14 -0
- package/dist/{whoami-z-76WaCP.mjs → whoami-BMAFa4es.mjs} +2 -2
- package/package.json +2 -2
- package/skills/wangxiaobao-knowledge-base/SKILL.md +105 -0
- package/skills/wangxiaobao-quick-qa/SKILL.md +4 -0
- package/skills/wangxiaobao-shared/SKILL.md +12 -5
- package/skills/wangxiaobao-visit-summary-query/SKILL.md +126 -0
- package/dist/visit-DoeECi8w.mjs +0 -11
package/README.md
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
# @puyinkai/xiaobao-cli
|
|
2
2
|
|
|
3
3
|
旺小宝 CLI —— [openclaw-xiaobao](https://github.com/puyinkai/openclaw-xiaobao)
|
|
4
|
-
plugin 的 host-agnostic
|
|
5
|
-
|
|
6
|
-
out 的 host)通过 stdout JSON 消费**。
|
|
4
|
+
plugin 的 host-agnostic 等价物。业务数据 / 问数 / 来访总结 / 知识库 等能力映射为
|
|
5
|
+
CLI 子命令,**人类直接敲也好用,AI agent(Claude Code / Codex / Cursor / OpenClaw /
|
|
6
|
+
任何能 shell out 的 host)通过 stdout JSON 消费**。
|
|
7
|
+
|
|
8
|
+
> 后端链路:CLI 调 `ai-open`(公网开放层 / OAuth 鉴权),ai-open 作为薄代理转发到内网
|
|
9
|
+
> 业务层 `wang-ai-mcp`。命令用法对调用方透明。
|
|
7
10
|
|
|
8
11
|
参考 [larksuite/cli](https://github.com/larksuite/cli) 范式,跟 OpenClaw plugin
|
|
9
12
|
解耦:plugin 这条线(`@puyinkai/openclaw-xiaobao`)保持现状,本 CLI 走 npm,
|
|
@@ -30,7 +33,7 @@ xiaobao-cli audio list --from "2026-05-01 00:00:00" --to "2026-05-02 00:00:00" -
|
|
|
30
33
|
> openclaw-xiaobao 老用户:CLI 默认从 `~/.openclaw/state/wangxiaobao/` fallback
|
|
31
34
|
> 读 token + active-project,**零迁移开箱即用**。新写操作落到 `~/.xiaobao/`。
|
|
32
35
|
|
|
33
|
-
##
|
|
36
|
+
## 能力一览
|
|
34
37
|
|
|
35
38
|
| 命令 | 对应 openclaw-xiaobao tool |
|
|
36
39
|
| --- | --- |
|
|
@@ -46,12 +49,17 @@ xiaobao-cli audio list --from "2026-05-01 00:00:00" --to "2026-05-02 00:00:00" -
|
|
|
46
49
|
| `visit list [--customer-id] [--from] [--to]` | `xiaobao_list_visits` |
|
|
47
50
|
| `focus list [--visit-ids] [--category] ...` | `xiaobao_list_customer_focus` |
|
|
48
51
|
| `resistance list [...]` | `xiaobao_list_customer_resistance` |
|
|
49
|
-
| `qa <prompt> [--thread-id <id>]` | `xiaobao_quick_qa
|
|
52
|
+
| `qa <prompt> [--thread-id <id>]` | `xiaobao_quick_qa`(底层已切 sql-agent) |
|
|
53
|
+
| `visit summary [--customer-id] [--visit-id] [--template] [--from] [--to]` | 新增 · 来访接待总结 |
|
|
54
|
+
| `kb search <query> [--k]` | 新增 · 知识库语义检索 |
|
|
55
|
+
| `kb docs [--title]` | 新增 · 知识库文档列表 |
|
|
56
|
+
| `kb doc <doc-id>` | 新增 · 知识库文档详情 |
|
|
57
|
+
| `kb doc-content <doc-id> [--offset] [--limit]` | 新增 · 知识库文档正文分页 |
|
|
50
58
|
| `api <METHOD> <path>` | `xiaobao_api` |
|
|
51
59
|
|
|
52
60
|
## 通用 flags
|
|
53
61
|
|
|
54
|
-
- `--format json|
|
|
62
|
+
- `--format toon|json|table` —— 默认 `toon`(省 token,适合 LLM 上下文);`json` 严格 JSON、agent/人类友好;`table` 暂未实现(回退 JSON)
|
|
55
63
|
- `--api-base <url>` / `--auth-base <url>` —— 覆盖默认(也可 env `XIAOBAO_API_BASE` / `XIAOBAO_AUTH_BASE`)
|
|
56
64
|
|
|
57
65
|
## 输出协议
|
|
@@ -73,8 +81,10 @@ xiaobao-cli audio list --from "2026-05-01 00:00:00" --to "2026-05-02 00:00:00" -
|
|
|
73
81
|
|
|
74
82
|
## skill 配套
|
|
75
83
|
|
|
76
|
-
`skills/`
|
|
77
|
-
只是调用从 plugin tool invoke 改为 shell out `xiaobao-cli
|
|
84
|
+
`skills/` 目录下的 SKILL.md 跟 cli 同包发布,跟 openclaw-xiaobao 那边镜像,
|
|
85
|
+
只是调用从 plugin tool invoke 改为 shell out `xiaobao-cli ...`。本次新增
|
|
86
|
+
`wangxiaobao-visit-summary-query`(来访接待总结)与 `wangxiaobao-knowledge-base`(知识库)
|
|
87
|
+
两个 skill;`wangxiaobao-quick-qa` 的问数底层由 fast-responder 切换为 sql-agent。
|
|
78
88
|
|
|
79
89
|
## License
|
|
80
90
|
|
|
@@ -2,7 +2,7 @@ import { a as resolveConfig } from "./device-flow-D6JVcEap.mjs";
|
|
|
2
2
|
import { t as xbApiFetch } from "./api-client-CDNjkArS.mjs";
|
|
3
3
|
import { t as loadActiveProject } from "./project-store-CKVJa54T.mjs";
|
|
4
4
|
import { t as tenantProjectHeaders } from "./headers-DSnR4sjk.mjs";
|
|
5
|
-
import { n as writeResult, t as writeError } from "./format-
|
|
5
|
+
import { n as writeResult, t as writeError } from "./format-CvKe7-yU.mjs";
|
|
6
6
|
import { defineCommand } from "citty";
|
|
7
7
|
//#region src/commands/api.ts
|
|
8
8
|
/**
|
|
@@ -69,7 +69,7 @@ var api_default = defineCommand({
|
|
|
69
69
|
"auth-base": { type: "string" },
|
|
70
70
|
format: {
|
|
71
71
|
type: "string",
|
|
72
|
-
default: "
|
|
72
|
+
default: "toon"
|
|
73
73
|
}
|
|
74
74
|
},
|
|
75
75
|
async run({ args }) {
|
|
@@ -6,8 +6,8 @@ var audio_default = defineCommand({
|
|
|
6
6
|
description: "录音元数据分页 / 单条文本查询"
|
|
7
7
|
},
|
|
8
8
|
subCommands: {
|
|
9
|
-
list: () => import("./list-
|
|
10
|
-
text: () => import("./text-
|
|
9
|
+
list: () => import("./list-CZVU6EVq.mjs").then((m) => m.default),
|
|
10
|
+
text: () => import("./text-bgoI1KC-.mjs").then((m) => m.default)
|
|
11
11
|
}
|
|
12
12
|
});
|
|
13
13
|
//#endregion
|
|
@@ -6,9 +6,9 @@ var auth_default = defineCommand({
|
|
|
6
6
|
description: "OAuth 登录 / 身份查询 / 登出(device flow)"
|
|
7
7
|
},
|
|
8
8
|
subCommands: {
|
|
9
|
-
login: () => import("./login-
|
|
10
|
-
whoami: () => import("./whoami-
|
|
11
|
-
logout: () => import("./logout-
|
|
9
|
+
login: () => import("./login-B5e9tJbS.mjs").then((m) => m.default),
|
|
10
|
+
whoami: () => import("./whoami-BMAFa4es.mjs").then((m) => m.default),
|
|
11
|
+
logout: () => import("./logout-Dz_FFIRP.mjs").then((m) => m.default)
|
|
12
12
|
}
|
|
13
13
|
});
|
|
14
14
|
//#endregion
|
package/dist/cli.mjs
CHANGED
|
@@ -7,27 +7,29 @@ import { defineCommand, runMain } from "citty";
|
|
|
7
7
|
/**
|
|
8
8
|
* xiaobao-cli entrypoint.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* Capabilities mapped from the openclaw-xiaobao plugin to CLI subcommands,
|
|
11
|
+
* plus visit-summary and knowledge-base queries — all proxied through
|
|
12
|
+
* ai-open → wang-ai-mcp. See README for the full command map.
|
|
12
13
|
*/
|
|
13
14
|
const pkgPath = join(dirname(fileURLToPath(import.meta.url)), "..", "package.json");
|
|
14
15
|
runMain(defineCommand({
|
|
15
16
|
meta: {
|
|
16
17
|
name: "xiaobao-cli",
|
|
17
18
|
version: JSON.parse(readFileSync(pkgPath, "utf8")).version,
|
|
18
|
-
description: "旺小宝 CLI — host-agnostic
|
|
19
|
+
description: "旺小宝 CLI — host-agnostic 业务数据 / 问数 / 来访总结 / 知识库 能力 (openclaw-xiaobao plugin 的 CLI 等价物)"
|
|
19
20
|
},
|
|
20
21
|
subCommands: {
|
|
21
|
-
auth: () => import("./auth-
|
|
22
|
-
project: () => import("./project-
|
|
23
|
-
consultant: () => import("./consultant-
|
|
24
|
-
audio: () => import("./audio-
|
|
25
|
-
customer: () => import("./customer-
|
|
26
|
-
visit: () => import("./visit-
|
|
27
|
-
focus: () => import("./focus-
|
|
28
|
-
resistance: () => import("./resistance-
|
|
29
|
-
qa: () => import("./qa-
|
|
30
|
-
|
|
22
|
+
auth: () => import("./auth-BYWDBat3.mjs").then((m) => m.default),
|
|
23
|
+
project: () => import("./project-C2fvEuDl.mjs").then((m) => m.default),
|
|
24
|
+
consultant: () => import("./consultant-DvH6ezCT.mjs").then((m) => m.default),
|
|
25
|
+
audio: () => import("./audio-DhEiStuy.mjs").then((m) => m.default),
|
|
26
|
+
customer: () => import("./customer-BtAtJyM8.mjs").then((m) => m.default),
|
|
27
|
+
visit: () => import("./visit-LX3B_OgE.mjs").then((m) => m.default),
|
|
28
|
+
focus: () => import("./focus-BmLvFWII.mjs").then((m) => m.default),
|
|
29
|
+
resistance: () => import("./resistance-BxOZNWbb.mjs").then((m) => m.default),
|
|
30
|
+
qa: () => import("./qa-C2TSTS-m.mjs").then((m) => m.default),
|
|
31
|
+
kb: () => import("./kb-B9IY8-fu.mjs").then((m) => m.default),
|
|
32
|
+
api: () => import("./api-DtFEKH3I.mjs").then((m) => m.default)
|
|
31
33
|
}
|
|
32
34
|
}));
|
|
33
35
|
//#endregion
|
|
@@ -5,7 +5,7 @@ var consultant_default = defineCommand({
|
|
|
5
5
|
name: "consultant",
|
|
6
6
|
description: "查询有权限的置业顾问列表"
|
|
7
7
|
},
|
|
8
|
-
subCommands: { list: () => import("./list-
|
|
8
|
+
subCommands: { list: () => import("./list-CiBpxZFs.mjs").then((m) => m.default) }
|
|
9
9
|
});
|
|
10
10
|
//#endregion
|
|
11
11
|
export { consultant_default as default };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as requireActiveProject } from "./project-store-CKVJa54T.mjs";
|
|
2
|
-
import { n as writeResult, t as writeError } from "./format-
|
|
2
|
+
import { n as writeResult, t as writeError } from "./format-CvKe7-yU.mjs";
|
|
3
3
|
import { defineCommand } from "citty";
|
|
4
4
|
//#region src/commands/project/current.ts
|
|
5
5
|
/**
|
|
@@ -18,7 +18,7 @@ var current_default = defineCommand({
|
|
|
18
18
|
},
|
|
19
19
|
args: { format: {
|
|
20
20
|
type: "string",
|
|
21
|
-
default: "
|
|
21
|
+
default: "toon"
|
|
22
22
|
} },
|
|
23
23
|
async run({ args }) {
|
|
24
24
|
try {
|
|
@@ -5,7 +5,7 @@ var customer_default = defineCommand({
|
|
|
5
5
|
name: "customer",
|
|
6
6
|
description: "客户画像分页查询"
|
|
7
7
|
},
|
|
8
|
-
subCommands: { list: () => import("./list-
|
|
8
|
+
subCommands: { list: () => import("./list-DDGGG2p2.mjs").then((m) => m.default) }
|
|
9
9
|
});
|
|
10
10
|
//#endregion
|
|
11
11
|
export { customer_default as default };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { a as resolveConfig } from "./device-flow-D6JVcEap.mjs";
|
|
2
|
+
import { t as xbApiFetch } from "./api-client-CDNjkArS.mjs";
|
|
3
|
+
import { n as requireActiveProject } from "./project-store-CKVJa54T.mjs";
|
|
4
|
+
import { t as tenantProjectHeaders } from "./headers-DSnR4sjk.mjs";
|
|
5
|
+
import { n as writeResult, t as writeError } from "./format-CvKe7-yU.mjs";
|
|
6
|
+
import { defineCommand } from "citty";
|
|
7
|
+
//#region src/commands/kb/doc.ts
|
|
8
|
+
/**
|
|
9
|
+
* `xiaobao-cli kb doc <doc-id>` — knowledge-base document detail via
|
|
10
|
+
* POST /ai-open/kb/docs/get. Fetched by docId. For the full body text use
|
|
11
|
+
* `kb doc-content` (paged).
|
|
12
|
+
*/
|
|
13
|
+
var doc_default = defineCommand({
|
|
14
|
+
meta: {
|
|
15
|
+
name: "doc",
|
|
16
|
+
description: "知识库文档详情(按 docId 直取)"
|
|
17
|
+
},
|
|
18
|
+
args: {
|
|
19
|
+
"doc-id": {
|
|
20
|
+
type: "positional",
|
|
21
|
+
required: true,
|
|
22
|
+
description: "文档 ID"
|
|
23
|
+
},
|
|
24
|
+
"api-base": { type: "string" },
|
|
25
|
+
"auth-base": { type: "string" },
|
|
26
|
+
format: {
|
|
27
|
+
type: "string",
|
|
28
|
+
default: "toon"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
async run({ args }) {
|
|
32
|
+
try {
|
|
33
|
+
writeResult(await xbApiFetch(resolveConfig({
|
|
34
|
+
apiBase: args["api-base"],
|
|
35
|
+
authBase: args["auth-base"]
|
|
36
|
+
}), "POST", "/ai-open/kb/docs/get", {
|
|
37
|
+
headers: tenantProjectHeaders(await requireActiveProject()),
|
|
38
|
+
body: { docId: Number(args["doc-id"]) }
|
|
39
|
+
}), args.format);
|
|
40
|
+
} catch (err) {
|
|
41
|
+
writeError(err, args.format);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
//#endregion
|
|
47
|
+
export { doc_default as default };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { a as resolveConfig } from "./device-flow-D6JVcEap.mjs";
|
|
2
|
+
import { t as xbApiFetch } from "./api-client-CDNjkArS.mjs";
|
|
3
|
+
import { n as requireActiveProject } from "./project-store-CKVJa54T.mjs";
|
|
4
|
+
import { t as tenantProjectHeaders } from "./headers-DSnR4sjk.mjs";
|
|
5
|
+
import { n as writeResult, t as writeError } from "./format-CvKe7-yU.mjs";
|
|
6
|
+
import { defineCommand } from "citty";
|
|
7
|
+
//#region src/commands/kb/doc-content.ts
|
|
8
|
+
/**
|
|
9
|
+
* `xiaobao-cli kb doc-content <doc-id>` — paged knowledge-base document body
|
|
10
|
+
* via POST /ai-open/kb/docs/content/query. Page through long documents with
|
|
11
|
+
* `--offset`/`--limit`; use the `hasMore` flag in the response to keep going.
|
|
12
|
+
*/
|
|
13
|
+
var doc_content_default = defineCommand({
|
|
14
|
+
meta: {
|
|
15
|
+
name: "doc-content",
|
|
16
|
+
description: "知识库文档正文分页(offset/limit 翻页,hasMore 续翻)"
|
|
17
|
+
},
|
|
18
|
+
args: {
|
|
19
|
+
"doc-id": {
|
|
20
|
+
type: "positional",
|
|
21
|
+
required: true,
|
|
22
|
+
description: "文档 ID"
|
|
23
|
+
},
|
|
24
|
+
offset: {
|
|
25
|
+
type: "string",
|
|
26
|
+
description: "内容偏移,默认 0"
|
|
27
|
+
},
|
|
28
|
+
limit: {
|
|
29
|
+
type: "string",
|
|
30
|
+
description: "内容长度,默认 1000,最大 2000"
|
|
31
|
+
},
|
|
32
|
+
"api-base": { type: "string" },
|
|
33
|
+
"auth-base": { type: "string" },
|
|
34
|
+
format: {
|
|
35
|
+
type: "string",
|
|
36
|
+
default: "toon"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
async run({ args }) {
|
|
40
|
+
try {
|
|
41
|
+
writeResult(await xbApiFetch(resolveConfig({
|
|
42
|
+
apiBase: args["api-base"],
|
|
43
|
+
authBase: args["auth-base"]
|
|
44
|
+
}), "POST", "/ai-open/kb/docs/content/query", {
|
|
45
|
+
headers: tenantProjectHeaders(await requireActiveProject()),
|
|
46
|
+
body: {
|
|
47
|
+
docId: Number(args["doc-id"]),
|
|
48
|
+
offset: args.offset != null ? Number(args.offset) : void 0,
|
|
49
|
+
limit: args.limit != null ? Number(args.limit) : void 0
|
|
50
|
+
}
|
|
51
|
+
}), args.format);
|
|
52
|
+
} catch (err) {
|
|
53
|
+
writeError(err, args.format);
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
//#endregion
|
|
59
|
+
export { doc_content_default as default };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { a as resolveConfig } from "./device-flow-D6JVcEap.mjs";
|
|
2
|
+
import { t as xbApiFetch } from "./api-client-CDNjkArS.mjs";
|
|
3
|
+
import { n as requireActiveProject } from "./project-store-CKVJa54T.mjs";
|
|
4
|
+
import { t as tenantProjectHeaders } from "./headers-DSnR4sjk.mjs";
|
|
5
|
+
import { n as writeResult, t as writeError } from "./format-CvKe7-yU.mjs";
|
|
6
|
+
import { defineCommand } from "citty";
|
|
7
|
+
//#region src/commands/kb/docs.ts
|
|
8
|
+
/**
|
|
9
|
+
* `xiaobao-cli kb docs` — list knowledge-base documents via
|
|
10
|
+
* POST /ai-open/kb/docs/query. Scoped to the active project. Use `--title`
|
|
11
|
+
* to filter by title keyword.
|
|
12
|
+
*/
|
|
13
|
+
var docs_default = defineCommand({
|
|
14
|
+
meta: {
|
|
15
|
+
name: "docs",
|
|
16
|
+
description: "知识库文档列表(按当前激活项目隔离)"
|
|
17
|
+
},
|
|
18
|
+
args: {
|
|
19
|
+
title: {
|
|
20
|
+
type: "string",
|
|
21
|
+
description: "标题关键字过滤(可选)"
|
|
22
|
+
},
|
|
23
|
+
"api-base": { type: "string" },
|
|
24
|
+
"auth-base": { type: "string" },
|
|
25
|
+
format: {
|
|
26
|
+
type: "string",
|
|
27
|
+
default: "toon"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
async run({ args }) {
|
|
31
|
+
try {
|
|
32
|
+
writeResult(await xbApiFetch(resolveConfig({
|
|
33
|
+
apiBase: args["api-base"],
|
|
34
|
+
authBase: args["auth-base"]
|
|
35
|
+
}), "POST", "/ai-open/kb/docs/query", {
|
|
36
|
+
headers: tenantProjectHeaders(await requireActiveProject()),
|
|
37
|
+
body: { title: args.title }
|
|
38
|
+
}), args.format);
|
|
39
|
+
} catch (err) {
|
|
40
|
+
writeError(err, args.format);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
//#endregion
|
|
46
|
+
export { docs_default as default };
|
|
@@ -5,7 +5,7 @@ var focus_default = defineCommand({
|
|
|
5
5
|
name: "focus",
|
|
6
6
|
description: "客户关注点标签分页查询"
|
|
7
7
|
},
|
|
8
|
-
subCommands: { list: () => import("./list-
|
|
8
|
+
subCommands: { list: () => import("./list-VJImXOzy.mjs").then((m) => m.default) }
|
|
9
9
|
});
|
|
10
10
|
//#endregion
|
|
11
11
|
export { focus_default as default };
|
|
@@ -560,21 +560,21 @@ function resolveOptions(options) {
|
|
|
560
560
|
/**
|
|
561
561
|
* Format a result payload to stdout in one of three flavours:
|
|
562
562
|
*
|
|
563
|
-
*
|
|
564
|
-
* toon TOON (Token-Oriented Object Notation) — ~30-50% fewer
|
|
563
|
+
* toon (default) TOON (Token-Oriented Object Notation) — ~30-50% fewer
|
|
565
564
|
* tokens on uniform array-of-objects (LLM context optimization)
|
|
565
|
+
* json pretty JSON, agent-friendly and human-OK
|
|
566
566
|
* table not implemented in 0.1.0 — falls back to pretty JSON
|
|
567
567
|
* (a v0.1.x target; pure cosmetic, doesn't affect agent flow)
|
|
568
568
|
*
|
|
569
569
|
* Errors / logs MUST NOT go through here — use stderr (console.error) so
|
|
570
570
|
* agents parsing stdout don't break.
|
|
571
571
|
*/
|
|
572
|
-
function writeResult(data, format = "
|
|
572
|
+
function writeResult(data, format = "toon") {
|
|
573
573
|
const text = normalize(format) === "toon" ? encode(data) : JSON.stringify(data, null, 2);
|
|
574
574
|
process.stdout.write(text + "\n");
|
|
575
575
|
}
|
|
576
576
|
/** Print an error structurally to stdout (still parseable) and human hint to stderr. */
|
|
577
|
-
function writeError(error, format = "
|
|
577
|
+
function writeError(error, format = "toon") {
|
|
578
578
|
const payload = serializeError(error);
|
|
579
579
|
const text = normalize(format) === "toon" ? encode(payload) : JSON.stringify(payload, null, 2);
|
|
580
580
|
process.stdout.write(text + "\n");
|
|
@@ -585,9 +585,9 @@ function writeError(error, format = "json") {
|
|
|
585
585
|
if (err.hint) process.stderr.write(`hint: ${err.hint}\n`);
|
|
586
586
|
}
|
|
587
587
|
function normalize(f) {
|
|
588
|
-
if (f === "
|
|
588
|
+
if (f === "json") return "json";
|
|
589
589
|
if (f === "table") return "table";
|
|
590
|
-
return "
|
|
590
|
+
return "toon";
|
|
591
591
|
}
|
|
592
592
|
function serializeError(error) {
|
|
593
593
|
if (error instanceof Error) {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { defineCommand } from "citty";
|
|
2
|
+
//#region src/commands/kb/index.ts
|
|
3
|
+
var kb_default = defineCommand({
|
|
4
|
+
meta: {
|
|
5
|
+
name: "kb",
|
|
6
|
+
description: "项目知识库:语义检索 / 文档列表 / 文档详情 / 文档正文分页"
|
|
7
|
+
},
|
|
8
|
+
subCommands: {
|
|
9
|
+
search: () => import("./search-CBWh8yKE.mjs").then((m) => m.default),
|
|
10
|
+
docs: () => import("./docs-C_sC8m3F.mjs").then((m) => m.default),
|
|
11
|
+
doc: () => import("./doc--iAF-laM.mjs").then((m) => m.default),
|
|
12
|
+
"doc-content": () => import("./doc-content-CqDVEgwX.mjs").then((m) => m.default)
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
//#endregion
|
|
16
|
+
export { kb_default as default };
|
|
@@ -2,7 +2,7 @@ import { a as resolveConfig } from "./device-flow-D6JVcEap.mjs";
|
|
|
2
2
|
import { t as xbApiFetch } from "./api-client-CDNjkArS.mjs";
|
|
3
3
|
import { n as requireActiveProject } from "./project-store-CKVJa54T.mjs";
|
|
4
4
|
import { t as tenantProjectHeaders } from "./headers-DSnR4sjk.mjs";
|
|
5
|
-
import { n as writeResult, t as writeError } from "./format-
|
|
5
|
+
import { n as writeResult, t as writeError } from "./format-CvKe7-yU.mjs";
|
|
6
6
|
import { n as mergeUserIds, r as toLocalDateTime, t as csvToArray } from "./util-CaPQBlNa.mjs";
|
|
7
7
|
import { defineCommand } from "citty";
|
|
8
8
|
//#region src/commands/audio/list.ts
|
|
@@ -49,7 +49,7 @@ var list_default = defineCommand({
|
|
|
49
49
|
"auth-base": { type: "string" },
|
|
50
50
|
format: {
|
|
51
51
|
type: "string",
|
|
52
|
-
default: "
|
|
52
|
+
default: "toon"
|
|
53
53
|
}
|
|
54
54
|
},
|
|
55
55
|
async run({ args }) {
|
|
@@ -2,7 +2,7 @@ import { a as resolveConfig } from "./device-flow-D6JVcEap.mjs";
|
|
|
2
2
|
import { t as xbApiFetch } from "./api-client-CDNjkArS.mjs";
|
|
3
3
|
import { n as requireActiveProject } from "./project-store-CKVJa54T.mjs";
|
|
4
4
|
import { t as tenantProjectHeaders } from "./headers-DSnR4sjk.mjs";
|
|
5
|
-
import { n as writeResult, t as writeError } from "./format-
|
|
5
|
+
import { n as writeResult, t as writeError } from "./format-CvKe7-yU.mjs";
|
|
6
6
|
import { defineCommand } from "citty";
|
|
7
7
|
//#region src/commands/consultant/list.ts
|
|
8
8
|
/**
|
|
@@ -22,7 +22,7 @@ var list_default = defineCommand({
|
|
|
22
22
|
"auth-base": { type: "string" },
|
|
23
23
|
format: {
|
|
24
24
|
type: "string",
|
|
25
|
-
default: "
|
|
25
|
+
default: "toon"
|
|
26
26
|
}
|
|
27
27
|
},
|
|
28
28
|
async run({ args }) {
|
|
@@ -2,7 +2,7 @@ import { a as resolveConfig } from "./device-flow-D6JVcEap.mjs";
|
|
|
2
2
|
import { t as xbApiFetch } from "./api-client-CDNjkArS.mjs";
|
|
3
3
|
import { n as requireActiveProject } from "./project-store-CKVJa54T.mjs";
|
|
4
4
|
import { t as tenantProjectHeaders } from "./headers-DSnR4sjk.mjs";
|
|
5
|
-
import { n as writeResult, t as writeError } from "./format-
|
|
5
|
+
import { n as writeResult, t as writeError } from "./format-CvKe7-yU.mjs";
|
|
6
6
|
import { r as toLocalDateTime } from "./util-CaPQBlNa.mjs";
|
|
7
7
|
import { defineCommand } from "citty";
|
|
8
8
|
//#region src/commands/customer/list.ts
|
|
@@ -60,7 +60,7 @@ var list_default = defineCommand({
|
|
|
60
60
|
"auth-base": { type: "string" },
|
|
61
61
|
format: {
|
|
62
62
|
type: "string",
|
|
63
|
-
default: "
|
|
63
|
+
default: "toon"
|
|
64
64
|
}
|
|
65
65
|
},
|
|
66
66
|
async run({ args }) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as resolveConfig } from "./device-flow-D6JVcEap.mjs";
|
|
2
2
|
import { t as xbApiFetch } from "./api-client-CDNjkArS.mjs";
|
|
3
|
-
import { n as writeResult, t as writeError } from "./format-
|
|
3
|
+
import { n as writeResult, t as writeError } from "./format-CvKe7-yU.mjs";
|
|
4
4
|
import { defineCommand } from "citty";
|
|
5
5
|
//#region src/commands/project/list.ts
|
|
6
6
|
/**
|
|
@@ -26,7 +26,7 @@ var list_default = defineCommand({
|
|
|
26
26
|
"auth-base": { type: "string" },
|
|
27
27
|
format: {
|
|
28
28
|
type: "string",
|
|
29
|
-
default: "
|
|
29
|
+
default: "toon"
|
|
30
30
|
}
|
|
31
31
|
},
|
|
32
32
|
async run({ args }) {
|
|
@@ -2,7 +2,7 @@ import { a as resolveConfig } from "./device-flow-D6JVcEap.mjs";
|
|
|
2
2
|
import { t as xbApiFetch } from "./api-client-CDNjkArS.mjs";
|
|
3
3
|
import { n as requireActiveProject } from "./project-store-CKVJa54T.mjs";
|
|
4
4
|
import { t as tenantProjectHeaders } from "./headers-DSnR4sjk.mjs";
|
|
5
|
-
import { n as writeResult, t as writeError } from "./format-
|
|
5
|
+
import { n as writeResult, t as writeError } from "./format-CvKe7-yU.mjs";
|
|
6
6
|
import { r as toLocalDateTime } from "./util-CaPQBlNa.mjs";
|
|
7
7
|
import { defineCommand } from "citty";
|
|
8
8
|
//#region src/commands/visit/list.ts
|
|
@@ -47,7 +47,7 @@ var list_default = defineCommand({
|
|
|
47
47
|
"auth-base": { type: "string" },
|
|
48
48
|
format: {
|
|
49
49
|
type: "string",
|
|
50
|
-
default: "
|
|
50
|
+
default: "toon"
|
|
51
51
|
}
|
|
52
52
|
},
|
|
53
53
|
async run({ args }) {
|
|
@@ -2,7 +2,7 @@ import { a as resolveConfig } from "./device-flow-D6JVcEap.mjs";
|
|
|
2
2
|
import { t as xbApiFetch } from "./api-client-CDNjkArS.mjs";
|
|
3
3
|
import { n as requireActiveProject } from "./project-store-CKVJa54T.mjs";
|
|
4
4
|
import { t as tenantProjectHeaders } from "./headers-DSnR4sjk.mjs";
|
|
5
|
-
import { n as writeResult, t as writeError } from "./format-
|
|
5
|
+
import { n as writeResult, t as writeError } from "./format-CvKe7-yU.mjs";
|
|
6
6
|
import { r as toLocalDateTime, t as csvToArray } from "./util-CaPQBlNa.mjs";
|
|
7
7
|
import { defineCommand } from "citty";
|
|
8
8
|
//#region src/commands/resistance/list.ts
|
|
@@ -59,7 +59,7 @@ var list_default = defineCommand({
|
|
|
59
59
|
"auth-base": { type: "string" },
|
|
60
60
|
format: {
|
|
61
61
|
type: "string",
|
|
62
|
-
default: "
|
|
62
|
+
default: "toon"
|
|
63
63
|
}
|
|
64
64
|
},
|
|
65
65
|
async run({ args }) {
|
|
@@ -2,7 +2,7 @@ import { a as resolveConfig } from "./device-flow-D6JVcEap.mjs";
|
|
|
2
2
|
import { t as xbApiFetch } from "./api-client-CDNjkArS.mjs";
|
|
3
3
|
import { n as requireActiveProject } from "./project-store-CKVJa54T.mjs";
|
|
4
4
|
import { t as tenantProjectHeaders } from "./headers-DSnR4sjk.mjs";
|
|
5
|
-
import { n as writeResult, t as writeError } from "./format-
|
|
5
|
+
import { n as writeResult, t as writeError } from "./format-CvKe7-yU.mjs";
|
|
6
6
|
import { r as toLocalDateTime, t as csvToArray } from "./util-CaPQBlNa.mjs";
|
|
7
7
|
import { defineCommand } from "citty";
|
|
8
8
|
//#region src/commands/focus/list.ts
|
|
@@ -59,7 +59,7 @@ var list_default = defineCommand({
|
|
|
59
59
|
"auth-base": { type: "string" },
|
|
60
60
|
format: {
|
|
61
61
|
type: "string",
|
|
62
|
-
default: "
|
|
62
|
+
default: "toon"
|
|
63
63
|
}
|
|
64
64
|
},
|
|
65
65
|
async run({ args }) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as resolveConfig, n as pollForToken, r as refreshToken, t as initiateDeviceAuthorization } from "./device-flow-D6JVcEap.mjs";
|
|
2
2
|
import { a as isAccessTokenValid, c as writePendingAuth, l as writeToken, n as clearPendingAuth, o as readPendingAuth, r as clearToken, s as readToken, t as NoPendingAuthError } from "./token-store-CXizLE2_.mjs";
|
|
3
|
-
import { n as writeResult, t as writeError } from "./format-
|
|
3
|
+
import { n as writeResult, t as writeError } from "./format-CvKe7-yU.mjs";
|
|
4
4
|
import { defineCommand } from "citty";
|
|
5
5
|
//#region src/commands/auth/login.ts
|
|
6
6
|
/**
|
|
@@ -56,7 +56,7 @@ var login_default = defineCommand({
|
|
|
56
56
|
},
|
|
57
57
|
format: {
|
|
58
58
|
type: "string",
|
|
59
|
-
default: "
|
|
59
|
+
default: "toon"
|
|
60
60
|
}
|
|
61
61
|
},
|
|
62
62
|
async run({ args }) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as resolveConfig, i as revokeRefreshToken } from "./device-flow-D6JVcEap.mjs";
|
|
2
2
|
import { n as clearPendingAuth, r as clearToken, s as readToken } from "./token-store-CXizLE2_.mjs";
|
|
3
|
-
import { n as writeResult, t as writeError } from "./format-
|
|
3
|
+
import { n as writeResult, t as writeError } from "./format-CvKe7-yU.mjs";
|
|
4
4
|
import { defineCommand } from "citty";
|
|
5
5
|
//#region src/commands/auth/logout.ts
|
|
6
6
|
/**
|
|
@@ -23,7 +23,7 @@ var logout_default = defineCommand({
|
|
|
23
23
|
},
|
|
24
24
|
format: {
|
|
25
25
|
type: "string",
|
|
26
|
-
default: "
|
|
26
|
+
default: "toon"
|
|
27
27
|
}
|
|
28
28
|
},
|
|
29
29
|
async run({ args }) {
|
|
@@ -6,9 +6,9 @@ var project_default = defineCommand({
|
|
|
6
6
|
description: "查询 / 切换激活项目"
|
|
7
7
|
},
|
|
8
8
|
subCommands: {
|
|
9
|
-
list: () => import("./list-
|
|
10
|
-
use: () => import("./use-
|
|
11
|
-
current: () => import("./current-
|
|
9
|
+
list: () => import("./list-DW4Sk-76.mjs").then((m) => m.default),
|
|
10
|
+
use: () => import("./use-xbTXVwXb.mjs").then((m) => m.default),
|
|
11
|
+
current: () => import("./current-gZDEGEmi.mjs").then((m) => m.default)
|
|
12
12
|
}
|
|
13
13
|
});
|
|
14
14
|
//#endregion
|
|
@@ -2,7 +2,7 @@ import { a as resolveConfig } from "./device-flow-D6JVcEap.mjs";
|
|
|
2
2
|
import { t as xbApiFetch } from "./api-client-CDNjkArS.mjs";
|
|
3
3
|
import { n as requireActiveProject } from "./project-store-CKVJa54T.mjs";
|
|
4
4
|
import { t as tenantProjectHeaders } from "./headers-DSnR4sjk.mjs";
|
|
5
|
-
import { n as writeResult, t as writeError } from "./format-
|
|
5
|
+
import { n as writeResult, t as writeError } from "./format-CvKe7-yU.mjs";
|
|
6
6
|
import { defineCommand } from "citty";
|
|
7
7
|
//#region src/commands/qa.ts
|
|
8
8
|
/**
|
|
@@ -11,6 +11,10 @@ import { defineCommand } from "citty";
|
|
|
11
11
|
* Natural-language Q&A over the active project's data — customers / visits /
|
|
12
12
|
* 挖需率 / 销冠 / 录音覆盖率 / KPIs. Wraps POST /ai-open/langchain/quick-qa/query.
|
|
13
13
|
*
|
|
14
|
+
* Backend note: ai-open now routes this endpoint to wang-ai-mcp's sql-agent
|
|
15
|
+
* (natural-language → SQL), replacing the legacy fast-responder. The request
|
|
16
|
+
* shape ({ prompt, thread_id }) and response are unchanged — transparent here.
|
|
17
|
+
*
|
|
14
18
|
* Multi-turn: pass back the `thread_id` from previous response via --thread-id
|
|
15
19
|
* for follow-ups. Timeout 30 min (backend can run long multi-step data lookups).
|
|
16
20
|
*/
|
|
@@ -33,7 +37,7 @@ var qa_default = defineCommand({
|
|
|
33
37
|
"auth-base": { type: "string" },
|
|
34
38
|
format: {
|
|
35
39
|
type: "string",
|
|
36
|
-
default: "
|
|
40
|
+
default: "toon"
|
|
37
41
|
}
|
|
38
42
|
},
|
|
39
43
|
async run({ args }) {
|
|
@@ -5,7 +5,7 @@ var resistance_default = defineCommand({
|
|
|
5
5
|
name: "resistance",
|
|
6
6
|
description: "客户抗性点标签分页查询"
|
|
7
7
|
},
|
|
8
|
-
subCommands: { list: () => import("./list-
|
|
8
|
+
subCommands: { list: () => import("./list-DmBz_8dR.mjs").then((m) => m.default) }
|
|
9
9
|
});
|
|
10
10
|
//#endregion
|
|
11
11
|
export { resistance_default as default };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { a as resolveConfig } from "./device-flow-D6JVcEap.mjs";
|
|
2
|
+
import { t as xbApiFetch } from "./api-client-CDNjkArS.mjs";
|
|
3
|
+
import { n as requireActiveProject } from "./project-store-CKVJa54T.mjs";
|
|
4
|
+
import { t as tenantProjectHeaders } from "./headers-DSnR4sjk.mjs";
|
|
5
|
+
import { n as writeResult, t as writeError } from "./format-CvKe7-yU.mjs";
|
|
6
|
+
import { t as csvToArray } from "./util-CaPQBlNa.mjs";
|
|
7
|
+
import { defineCommand } from "citty";
|
|
8
|
+
//#region src/commands/kb/search.ts
|
|
9
|
+
/**
|
|
10
|
+
* `xiaobao-cli kb search <query>` — semantic knowledge-base retrieval via
|
|
11
|
+
* POST /ai-open/kb/search. Returns ranked chunks (not full documents),
|
|
12
|
+
* scoped to the active project.
|
|
13
|
+
*/
|
|
14
|
+
var search_default = defineCommand({
|
|
15
|
+
meta: {
|
|
16
|
+
name: "search",
|
|
17
|
+
description: "知识库语义检索(返回 chunk,按当前激活项目隔离)"
|
|
18
|
+
},
|
|
19
|
+
args: {
|
|
20
|
+
query: {
|
|
21
|
+
type: "positional",
|
|
22
|
+
required: true,
|
|
23
|
+
description: "检索 query"
|
|
24
|
+
},
|
|
25
|
+
k: {
|
|
26
|
+
type: "string",
|
|
27
|
+
description: "返回 chunk 数量,默认 5,最大 20"
|
|
28
|
+
},
|
|
29
|
+
"chunk-types": {
|
|
30
|
+
type: "string",
|
|
31
|
+
description: "CSV: chunk 类型过滤"
|
|
32
|
+
},
|
|
33
|
+
"doc-ids": {
|
|
34
|
+
type: "string",
|
|
35
|
+
description: "CSV: 文档 ID 过滤"
|
|
36
|
+
},
|
|
37
|
+
"enable-rerank": {
|
|
38
|
+
type: "boolean",
|
|
39
|
+
description: "是否启用 rerank"
|
|
40
|
+
},
|
|
41
|
+
"rerank-threshold": {
|
|
42
|
+
type: "string",
|
|
43
|
+
description: "rerank 阈值(小数)"
|
|
44
|
+
},
|
|
45
|
+
"api-base": { type: "string" },
|
|
46
|
+
"auth-base": { type: "string" },
|
|
47
|
+
format: {
|
|
48
|
+
type: "string",
|
|
49
|
+
default: "toon"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
async run({ args }) {
|
|
53
|
+
try {
|
|
54
|
+
writeResult(await xbApiFetch(resolveConfig({
|
|
55
|
+
apiBase: args["api-base"],
|
|
56
|
+
authBase: args["auth-base"]
|
|
57
|
+
}), "POST", "/ai-open/kb/search", {
|
|
58
|
+
headers: tenantProjectHeaders(await requireActiveProject()),
|
|
59
|
+
body: {
|
|
60
|
+
query: String(args.query),
|
|
61
|
+
k: args.k != null ? Number(args.k) : void 0,
|
|
62
|
+
chunkTypes: csvToArray(args["chunk-types"]),
|
|
63
|
+
docIds: csvToArray(args["doc-ids"]),
|
|
64
|
+
enableRerank: args["enable-rerank"] ? true : void 0,
|
|
65
|
+
rerankThreshold: args["rerank-threshold"] != null ? Number(args["rerank-threshold"]) : void 0
|
|
66
|
+
}
|
|
67
|
+
}), args.format);
|
|
68
|
+
} catch (err) {
|
|
69
|
+
writeError(err, args.format);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
//#endregion
|
|
75
|
+
export { search_default as default };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { a as resolveConfig } from "./device-flow-D6JVcEap.mjs";
|
|
2
|
+
import { t as xbApiFetch } from "./api-client-CDNjkArS.mjs";
|
|
3
|
+
import { n as requireActiveProject } from "./project-store-CKVJa54T.mjs";
|
|
4
|
+
import { t as tenantProjectHeaders } from "./headers-DSnR4sjk.mjs";
|
|
5
|
+
import { n as writeResult, t as writeError } from "./format-CvKe7-yU.mjs";
|
|
6
|
+
import { r as toLocalDateTime } from "./util-CaPQBlNa.mjs";
|
|
7
|
+
import { defineCommand } from "citty";
|
|
8
|
+
//#region src/commands/visit/summary.ts
|
|
9
|
+
/**
|
|
10
|
+
* `xiaobao-cli visit summary` — page visit reception-summaries via
|
|
11
|
+
* POST /ai-open/visits/summary.
|
|
12
|
+
*
|
|
13
|
+
* Returns customer × visit × template-summary nesting, paged by visit_id.
|
|
14
|
+
* `--template` selects a specific reception-summary template (exact match on
|
|
15
|
+
* the template name, not a free-text question). When `--visit-id` is omitted,
|
|
16
|
+
* `--from`/`--to` are required and the window must be ≤ 7 days (enforced
|
|
17
|
+
* downstream by wang-ai-mcp).
|
|
18
|
+
*/
|
|
19
|
+
var summary_default = defineCommand({
|
|
20
|
+
meta: {
|
|
21
|
+
name: "summary",
|
|
22
|
+
description: "来访接待总结分页查询(客户×来访×模板总结,按 visit_id 分页)"
|
|
23
|
+
},
|
|
24
|
+
args: {
|
|
25
|
+
"customer-id": {
|
|
26
|
+
type: "string",
|
|
27
|
+
description: "客户 ID(wang_id)精确过滤"
|
|
28
|
+
},
|
|
29
|
+
"visit-id": {
|
|
30
|
+
type: "string",
|
|
31
|
+
description: "来访 ID 精确过滤;传了它 from/to 可省略"
|
|
32
|
+
},
|
|
33
|
+
from: {
|
|
34
|
+
type: "string",
|
|
35
|
+
description: "来访时间下限(含);visit-id 为空时必填"
|
|
36
|
+
},
|
|
37
|
+
to: {
|
|
38
|
+
type: "string",
|
|
39
|
+
description: "来访时间上限(不含);visit-id 为空时必填"
|
|
40
|
+
},
|
|
41
|
+
template: {
|
|
42
|
+
type: "string",
|
|
43
|
+
description: "指定查询某个接待总结模板的结果(精确匹配模板名,非自由问句)"
|
|
44
|
+
},
|
|
45
|
+
page: {
|
|
46
|
+
type: "string",
|
|
47
|
+
default: "1"
|
|
48
|
+
},
|
|
49
|
+
size: {
|
|
50
|
+
type: "string",
|
|
51
|
+
default: "10"
|
|
52
|
+
},
|
|
53
|
+
"api-base": { type: "string" },
|
|
54
|
+
"auth-base": { type: "string" },
|
|
55
|
+
format: {
|
|
56
|
+
type: "string",
|
|
57
|
+
default: "toon"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
async run({ args }) {
|
|
61
|
+
try {
|
|
62
|
+
writeResult(await xbApiFetch(resolveConfig({
|
|
63
|
+
apiBase: args["api-base"],
|
|
64
|
+
authBase: args["auth-base"]
|
|
65
|
+
}), "POST", "/ai-open/visits/summary", {
|
|
66
|
+
headers: tenantProjectHeaders(await requireActiveProject()),
|
|
67
|
+
body: {
|
|
68
|
+
wangId: args["customer-id"],
|
|
69
|
+
visitId: args["visit-id"],
|
|
70
|
+
fromDate: toLocalDateTime(args.from),
|
|
71
|
+
toDate: toLocalDateTime(args.to),
|
|
72
|
+
template: args.template,
|
|
73
|
+
page: Number(args.page),
|
|
74
|
+
size: Number(args.size)
|
|
75
|
+
}
|
|
76
|
+
}), args.format);
|
|
77
|
+
} catch (err) {
|
|
78
|
+
writeError(err, args.format);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
//#endregion
|
|
84
|
+
export { summary_default as default };
|
|
@@ -2,7 +2,7 @@ import { a as resolveConfig } from "./device-flow-D6JVcEap.mjs";
|
|
|
2
2
|
import { t as xbApiFetch } from "./api-client-CDNjkArS.mjs";
|
|
3
3
|
import { n as requireActiveProject } from "./project-store-CKVJa54T.mjs";
|
|
4
4
|
import { t as tenantProjectHeaders } from "./headers-DSnR4sjk.mjs";
|
|
5
|
-
import { n as writeResult, t as writeError } from "./format-
|
|
5
|
+
import { n as writeResult, t as writeError } from "./format-CvKe7-yU.mjs";
|
|
6
6
|
import { defineCommand } from "citty";
|
|
7
7
|
//#region src/commands/audio/text.ts
|
|
8
8
|
/**
|
|
@@ -27,7 +27,7 @@ var text_default = defineCommand({
|
|
|
27
27
|
"auth-base": { type: "string" },
|
|
28
28
|
format: {
|
|
29
29
|
type: "string",
|
|
30
|
-
default: "
|
|
30
|
+
default: "toon"
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
33
|
async run({ args }) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as saveActiveProject } from "./project-store-CKVJa54T.mjs";
|
|
2
|
-
import { n as writeResult, t as writeError } from "./format-
|
|
2
|
+
import { n as writeResult, t as writeError } from "./format-CvKe7-yU.mjs";
|
|
3
3
|
import { defineCommand } from "citty";
|
|
4
4
|
//#region src/commands/project/use.ts
|
|
5
5
|
/**
|
|
@@ -35,7 +35,7 @@ var use_default = defineCommand({
|
|
|
35
35
|
},
|
|
36
36
|
format: {
|
|
37
37
|
type: "string",
|
|
38
|
-
default: "
|
|
38
|
+
default: "toon"
|
|
39
39
|
}
|
|
40
40
|
},
|
|
41
41
|
async run({ args }) {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { defineCommand } from "citty";
|
|
2
|
+
//#region src/commands/visit/index.ts
|
|
3
|
+
var visit_default = defineCommand({
|
|
4
|
+
meta: {
|
|
5
|
+
name: "visit",
|
|
6
|
+
description: "客户来访分页查询 / 来访接待总结"
|
|
7
|
+
},
|
|
8
|
+
subCommands: {
|
|
9
|
+
list: () => import("./list-DbReQZE2.mjs").then((m) => m.default),
|
|
10
|
+
summary: () => import("./summary-CAm-WDNF.mjs").then((m) => m.default)
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
//#endregion
|
|
14
|
+
export { visit_default as default };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { i as decodeJwtPayload, s as readToken } from "./token-store-CXizLE2_.mjs";
|
|
2
|
-
import { n as writeResult, t as writeError } from "./format-
|
|
2
|
+
import { n as writeResult, t as writeError } from "./format-CvKe7-yU.mjs";
|
|
3
3
|
import { defineCommand } from "citty";
|
|
4
4
|
//#region src/commands/auth/whoami.ts
|
|
5
5
|
/**
|
|
@@ -15,7 +15,7 @@ var whoami_default = defineCommand({
|
|
|
15
15
|
},
|
|
16
16
|
args: { format: {
|
|
17
17
|
type: "string",
|
|
18
|
-
default: "
|
|
18
|
+
default: "toon"
|
|
19
19
|
} },
|
|
20
20
|
async run({ args }) {
|
|
21
21
|
try {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@puyinkai/xiaobao-cli",
|
|
3
|
-
"version": "0.1
|
|
4
|
-
"description": "旺小宝 CLI — host-agnostic
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "旺小宝 CLI — host-agnostic 业务数据 / 问数 / 来访总结 / 知识库 能力 (openclaw-xiaobao plugin 的 CLI 等价物)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"xiaobao-cli": "./dist/cli.mjs"
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wangxiaobao-knowledge-base
|
|
3
|
+
version: 0.1.0
|
|
4
|
+
description: "旺小宝项目知识库:语义检索项目知识 chunk(kb search)、列文档(kb docs)、看文档详情(kb doc)、分页读文档正文(kb doc-content)。search/docs 按当前激活项目隔离;doc/doc-content 按 docId 直取。只读、无副作用。高频命令: xiaobao-cli kb search '<query>' [--k N]; xiaobao-cli kb docs [--title <kw>]; xiaobao-cli kb doc <doc-id>; xiaobao-cli kb doc-content <doc-id> [--offset N] [--limit N]。何时用:用户问项目资料/楼盘知识/销售政策/户型文档/物料/知识库里有没有讲过X/某文档具体写了啥/帮我查下资料。注:search 返回 chunk 不是全文,要逐段读全文用 doc-content 翻页(看 hasMore 续翻);k 默认 5 上限 20;"
|
|
5
|
+
metadata:
|
|
6
|
+
requires:
|
|
7
|
+
bins: ["xiaobao-cli"]
|
|
8
|
+
cliHelp: "xiaobao-cli kb --help"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# 旺小宝项目知识库
|
|
12
|
+
|
|
13
|
+
> **CRITICAL** —— 跑命令前 MUST 先用 Read tool 读取 [`../wangxiaobao-shared/SKILL.md`](../wangxiaobao-shared/SKILL.md)(一份共享文档讲清安装 / 登录 / 选项目 / 错误码 / 输出协议等所有 xiaobao-cli 命令通用的前置约定)。
|
|
14
|
+
|
|
15
|
+
跑 `xiaobao-cli kb *` 检索 / 浏览当前激活项目的知识库(楼盘资料、政策、户型、物料等)。
|
|
16
|
+
|
|
17
|
+
## 执行前必读
|
|
18
|
+
|
|
19
|
+
- 必须有有效 token:先调 `xiaobao-cli auth whoami`;未登录就走 `auth login --no-wait` split-flow(见 wangxiaobao-shared)
|
|
20
|
+
- **必须有激活项目**:`kb search` / `kb docs` 按当前激活项目(estate)隔离知识;`kb doc` / `kb doc-content` 按 docId 直取(项目级而非顾问级隔离——任何登录用户按 docId 可读)
|
|
21
|
+
- **只读**:不写文件、不出报告
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 快速索引:意图 → 工具
|
|
26
|
+
|
|
27
|
+
| 用户意图 | 命令 | 关键参数 |
|
|
28
|
+
| --- | --- | --- |
|
|
29
|
+
| 知识库里有没有讲某主题 / 找答案 | `xiaobao-cli kb search` | `query` + `--k` |
|
|
30
|
+
| 列项目有哪些文档 | `xiaobao-cli kb docs` | `--title 关键字`(可选) |
|
|
31
|
+
| 看某文档的元信息 | `xiaobao-cli kb doc` | `<doc-id>` |
|
|
32
|
+
| 逐段读某文档全文 | `xiaobao-cli kb doc-content` | `<doc-id>` + `--offset` / `--limit` |
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 核心约束
|
|
37
|
+
|
|
38
|
+
### 1. search 返回 chunk,不是全文
|
|
39
|
+
|
|
40
|
+
`kb search` 走语义检索,返回最相关的若干 **chunk(片段)**,用于快速回答"知识库里怎么说 X"。要读某篇文档的完整内容,先 `kb docs` 找到 `docId`,再 `kb doc-content` 翻页读全文。
|
|
41
|
+
|
|
42
|
+
### 2. doc-content 用 offset/limit 翻页
|
|
43
|
+
|
|
44
|
+
正文可能很长,`kb doc-content` 按 `offset`/`limit` 分页(limit 默认 1000、最大 2000)。响应里 `hasMore=true` 说明还有后续,把 `offset` 加上已读长度继续翻,直到 `hasMore=false`。
|
|
45
|
+
|
|
46
|
+
### 3. k 默认 5,上限 20
|
|
47
|
+
|
|
48
|
+
`kb search --k` 控制返回 chunk 数;默认 5,最大 20。问题宽泛时调大 k,精确查证时用小 k。
|
|
49
|
+
|
|
50
|
+
### 4. 响应字段重点
|
|
51
|
+
|
|
52
|
+
`kb search`:
|
|
53
|
+
```jsonc
|
|
54
|
+
{ "code": "0", "data": {
|
|
55
|
+
"query": "学区", "tenantId": "...", "estateId": "...",
|
|
56
|
+
"chunks": [
|
|
57
|
+
{ "pageContent": "本项目对口 XX 小学...", "summary": "...", "sourceId": "123", "sourceType": "doc", "metadata": {...} }
|
|
58
|
+
] } }
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`kb docs`:`data.docs[]`,每项 `{ docId, title }`。
|
|
62
|
+
|
|
63
|
+
`kb doc`:`data` = `{ id, title, fileName, description, enabled, parseStatus, createdAt, updatedAt }`。
|
|
64
|
+
|
|
65
|
+
`kb doc-content`:`data` = `{ docId, offset, limit, totalLength, hasMore, content }`。
|
|
66
|
+
|
|
67
|
+
CLI 都再包一层 → 实际读 `resp.data.data.*`。
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 使用场景示例
|
|
72
|
+
|
|
73
|
+
### 场景 1:知识库里关于学区怎么说
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
xiaobao-cli kb search "学区 对口小学" --k 5
|
|
77
|
+
```
|
|
78
|
+
把命中的 `chunks[].pageContent` 综合成一段回答,必要时标注来源 `sourceId`。
|
|
79
|
+
|
|
80
|
+
### 场景 2:找户型相关文档并读全文
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# step 1: 找文档
|
|
84
|
+
xiaobao-cli kb docs --title 户型
|
|
85
|
+
# step 2: 假设 docId = 88,逐段读
|
|
86
|
+
xiaobao-cli kb doc-content 88 --offset 0 --limit 2000
|
|
87
|
+
# 若 hasMore=true,继续
|
|
88
|
+
xiaobao-cli kb doc-content 88 --offset 2000 --limit 2000
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 场景 3:看某文档元信息
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
xiaobao-cli kb doc 88
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## 常见错误与排查
|
|
100
|
+
|
|
101
|
+
- **`error: 'NO_ACTIVE_PROJECT'`** — 跑 `wangxiaobao-switch-project` skill(search/docs 需要激活项目)
|
|
102
|
+
- **401 / token 过期** — 走 `auth login --no-wait --force` split-flow 重登
|
|
103
|
+
- **search 命中为空 / chunks 为空** — 换关键词或调大 `--k`;该项目知识库可能尚未入库相关内容
|
|
104
|
+
- **doc-content 读不全** — 看 `hasMore`,按 `offset` 继续翻页
|
|
105
|
+
- **用户其实想问业务数据(客户/来访/业绩)** — 那是 `wangxiaobao-quick-qa`,不是知识库
|
|
@@ -15,6 +15,10 @@ metadata:
|
|
|
15
15
|
跑 `xiaobao-cli qa` 用自然语言问当前激活项目的业务数据。
|
|
16
16
|
零副作用,不写文件、不动 wiki,所以用错也没成本,鼓励放心调用。
|
|
17
17
|
|
|
18
|
+
> **后端说明**:问数底层已由旧的 fast-responder 升级为 **sql-agent**(自然语言 → SQL,
|
|
19
|
+
> 由 ai-open 代理到 wang-ai-mcp)。行为对调用方**透明**——请求 `{ prompt, thread_id }`
|
|
20
|
+
> 与响应结构(含 `type: "quick-qa"`)都不变,多轮 `--thread-id` 续接照旧。
|
|
21
|
+
|
|
18
22
|
## 执行前必读
|
|
19
23
|
|
|
20
24
|
- 必须有有效 token:先调 `xiaobao-cli auth whoami`;未登录 / 过期就走 `auth login --no-wait` split-flow(见 wangxiaobao-shared)
|
|
@@ -87,7 +87,7 @@ xiaobao-cli project current # 显示当前激活的 tenant/project + updatedAt
|
|
|
87
87
|
|
|
88
88
|
| 流 | 内容 |
|
|
89
89
|
| --- | --- |
|
|
90
|
-
| **stdout** | 结果 /
|
|
90
|
+
| **stdout** | 结果 / 错误对象,默认 **TOON 格式**(省 token);`--format json` 切回 JSON。均可机器解析 |
|
|
91
91
|
| **stderr** | 进度 / 人类友好错误提示 / verification URL 等。Agent 一般忽略 |
|
|
92
92
|
| **exit code** | 0 = 成功;非 0 = 失败(业务错误 / 参数错 / 网络错) |
|
|
93
93
|
|
|
@@ -97,8 +97,8 @@ Agent 消费时**只 parse stdout JSON**,stderr 是辅助。
|
|
|
97
97
|
|
|
98
98
|
| 值 | 用途 |
|
|
99
99
|
| --- | --- |
|
|
100
|
-
| `
|
|
101
|
-
| `
|
|
100
|
+
| `toon`(默认) | TOON 格式,uniform array of objects 省 30-50% token(LLM 上下文优化) |
|
|
101
|
+
| `json` | pretty JSON,agent / 人类都能读;需要严格 JSON 时显式加 `--format json` |
|
|
102
102
|
|
|
103
103
|
## 错误对象结构
|
|
104
104
|
|
|
@@ -155,8 +155,8 @@ openclaw 的副本(保留 plugin session 完整性)。`auth logout` 例外
|
|
|
155
155
|
|
|
156
156
|
## 数据权限隔离
|
|
157
157
|
|
|
158
|
-
`audio list` / `customer list` / `visit list` / `
|
|
159
|
-
`consultant list` 所有业务命令的后端都按**当前登录用户的授权范围**过滤数据:
|
|
158
|
+
`audio list` / `customer list` / `visit list` / `visit summary` / `focus list` /
|
|
159
|
+
`resistance list` / `consultant list` / `qa` 所有业务命令的后端都按**当前登录用户的授权范围**过滤数据:
|
|
160
160
|
|
|
161
161
|
- 普通顾问:只看自己名下
|
|
162
162
|
- 团队长:看本团队
|
|
@@ -165,6 +165,13 @@ openclaw 的副本(保留 plugin session 完整性)。`auth logout` 例外
|
|
|
165
165
|
`total: 0` 不一定是"没数据",也可能是**当前账号无权访问**。看不到的客户 / 顾问
|
|
166
166
|
不是 bug,是设计如此。要扩权限找管理员。
|
|
167
167
|
|
|
168
|
+
**例外 —— `kb *`(知识库)是项目级隔离**:`kb search` / `kb docs` 按当前激活项目(estate)
|
|
169
|
+
返回该项目知识,不按顾问授权范围细分;`kb doc` / `kb doc-content` 按 docId 直取。
|
|
170
|
+
知识库面向全项目,不存在"看不到别人名下"的概念。
|
|
171
|
+
|
|
172
|
+
> 后端链路:上述命令统一经 `ai-open`(公网开放层 / 鉴权)代理到内网业务层
|
|
173
|
+
> `wang-ai-mcp`,对调用方透明,命令用法不变。
|
|
174
|
+
|
|
168
175
|
## 时间格式
|
|
169
176
|
|
|
170
177
|
所有 `--from` / `--to` 用 `yyyy-MM-dd HH:mm:ss`(空格分隔,**不带时区**)。
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wangxiaobao-visit-summary-query
|
|
3
|
+
version: 0.1.0
|
|
4
|
+
description: "旺小宝来访接待总结查询:按 客户ID(wang_id)/来访ID/时间窗(≤7天)/模板(template) 分页拉取每次来访的 AI 接待总结,按 客户×来访×总结项 三层嵌套(每个总结项 question=模板名、reply=该模板的总结答案)。--template 指定查询某个接待总结模板的结果(精确匹配模板名,非自由问句)。只读、不写文件、无副作用。高频命令: xiaobao-cli visit summary [--customer-id <id>] [--visit-id <id>] [--from <date>] [--to <date>] [--template <模板名>] [--page N] [--size N]。何时用:用户问某客户上次来访聊了啥/这次接待总结/接待要点/AI 怎么总结这次到访/某模板(如\"客户需求\"\"抗性分析\")的总结结果/最近来访的接待小结。注:visit-id 为空时 from/to 必填且窗口≤7天;customer-id 先用 xiaobao-cli customer list 反查 wang_id;要来访列表/录音走 visit-query;要录音原文走 audio-query。"
|
|
5
|
+
metadata:
|
|
6
|
+
requires:
|
|
7
|
+
bins: ["xiaobao-cli"]
|
|
8
|
+
cliHelp: "xiaobao-cli visit summary --help"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# 旺小宝来访接待总结查询
|
|
12
|
+
|
|
13
|
+
> **CRITICAL** —— 跑命令前 MUST 先用 Read tool 读取 [`../wangxiaobao-shared/SKILL.md`](../wangxiaobao-shared/SKILL.md)(一份共享文档讲清安装 / 登录 / 选项目 / 错误码 / 输出协议等所有 xiaobao-cli 命令通用的前置约定)。
|
|
14
|
+
|
|
15
|
+
跑 `xiaobao-cli visit summary` 查当前激活项目里每次来访的 **AI 接待总结**(模板中心按模板生成的 question → reply)。
|
|
16
|
+
|
|
17
|
+
## 执行前必读
|
|
18
|
+
|
|
19
|
+
- 必须有有效 token:先调 `xiaobao-cli auth whoami`;未登录就走 `auth login --no-wait` split-flow(见 wangxiaobao-shared)
|
|
20
|
+
- **必须有激活项目**:命令内部自动读,缺失返回 `NO_ACTIVE_PROJECT`
|
|
21
|
+
- **数据权限隔离**:跟来访接口一样,按当前用户授权可见顾问范围过滤
|
|
22
|
+
- **时间窗 ≤ 7 天**:`visit-id` 为空时 `from`/`to` 必填,且窗口最长 7 天(超出后端自动截断为 to 往前 7 天)
|
|
23
|
+
- LocalDateTime 格式:`yyyy-MM-dd HH:mm:ss`(空格分隔),CLI 自动转
|
|
24
|
+
- **不要**写文件、出报告
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 快速索引:意图 → 工具
|
|
29
|
+
|
|
30
|
+
| 用户意图 | 命令 | 关键参数 |
|
|
31
|
+
| --- | --- | --- |
|
|
32
|
+
| 看某次来访的接待总结 | `xiaobao-cli visit summary` | `--visit-id <id>`(from/to 可省) |
|
|
33
|
+
| 看某客户近期来访总结 | `xiaobao-cli customer list` → `xiaobao-cli visit summary` | `--customer-id 反查的 wang_id` + 时间窗 |
|
|
34
|
+
| 看某时间窗内全部接待总结 | `xiaobao-cli visit summary` | `--from` / `--to`(≤7 天) |
|
|
35
|
+
| 只看某个模板的总结结果 | `xiaobao-cli visit summary` | `--template "客户需求"` |
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 核心约束
|
|
40
|
+
|
|
41
|
+
### 1. visit-id 优先;无 visit-id 时时间窗必填且 ≤ 7 天
|
|
42
|
+
|
|
43
|
+
- 已知具体某次来访 → `--visit-id`,可省略时间窗。
|
|
44
|
+
- 否则 `--from`/`--to` 必填;窗口跨度超 7 天会被后端截断(只保留靠近 `to` 的最后 7 天)。
|
|
45
|
+
|
|
46
|
+
| 用户说法 | fromDate / toDate |
|
|
47
|
+
| --- | --- |
|
|
48
|
+
| "今天来访总结" | 今天 00:00:00 / 明天 00:00:00 |
|
|
49
|
+
| "本周接待小结" | 周一 00:00:00 / 今天 23:59:59 |
|
|
50
|
+
| "最近一次来访" | 先 `visit list` 拿最近 visitId,再按 `--visit-id` 查 |
|
|
51
|
+
|
|
52
|
+
### 2. 客户 ID 用 customer list 反查
|
|
53
|
+
|
|
54
|
+
用户说"李女士上次来访聊了啥"——先 `xiaobao-cli customer list --customer-name 李女士` 反查 `wang_id`,再 `xiaobao-cli visit summary --customer-id <wang_id> --from ... --to ...`。
|
|
55
|
+
|
|
56
|
+
### 3. --template 是模板名精确匹配
|
|
57
|
+
|
|
58
|
+
`--template` 指定查询**某个接待总结模板**的结果(如 "客户需求"、"抗性分析"、"下一步跟进建议"),精确匹配模板名,不是自由问句。不传则返回该次来访的全部模板总结。要列出有哪些模板,先不带 `--template` 查一次,从返回的 `summaries[].question` 看模板名。
|
|
59
|
+
|
|
60
|
+
### 4. 按 visit_id 分页
|
|
61
|
+
|
|
62
|
+
`page` 从 1 开始,`size` 默认 10、**上限 100**。分页粒度是来访(visit_id),不是客户也不是总结条目。
|
|
63
|
+
|
|
64
|
+
### 5. 响应字段重点
|
|
65
|
+
|
|
66
|
+
```jsonc
|
|
67
|
+
{
|
|
68
|
+
"code": "0",
|
|
69
|
+
"data": {
|
|
70
|
+
"page": 1, "size": 10, "total": 23, // total = 命中的来访数
|
|
71
|
+
"content": [
|
|
72
|
+
{
|
|
73
|
+
"wangId": "1685535452481236993", // 客户 ID
|
|
74
|
+
"visits": [
|
|
75
|
+
{
|
|
76
|
+
"visitId": "...",
|
|
77
|
+
"visitTime": "2026-05-13 14:01:03",
|
|
78
|
+
"summaries": [ // ★ 该次来访的模板总结列表
|
|
79
|
+
{ "question": "客户需求", "reply": "关注三房、预算 300 万以内、看重学区..." },
|
|
80
|
+
{ "question": "抗性分析", "reply": "对楼层和价格有顾虑..." }
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
CLI 又包一层 → `resp.data.data.content`。每个总结项 `question` = 模板名、`reply` = 该模板的 AI 总结答案。展示给用户时按 客户 → 来访 → 模板 三层组织。
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 使用场景示例
|
|
95
|
+
|
|
96
|
+
### 场景 1:看某次来访的接待总结
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
xiaobao-cli visit summary --visit-id 998877
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 场景 2:李女士本周来访都聊了什么
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# step 1: 反查 wang_id
|
|
106
|
+
xiaobao-cli customer list --customer-name 李女士 --size 20
|
|
107
|
+
# step 2: 用 wang_id + 本周时间窗
|
|
108
|
+
xiaobao-cli visit summary --customer-id 270072120829026305 --from "2026-05-12 00:00:00" --to "2026-05-16 23:59:59"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 场景 3:只看"客户需求"模板的总结
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
xiaobao-cli visit summary --from "2026-05-13 00:00:00" --to "2026-05-14 00:00:00" --template "客户需求"
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## 常见错误与排查
|
|
120
|
+
|
|
121
|
+
- **`error: 'NO_ACTIVE_PROJECT'`** — 跑 `wangxiaobao-switch-project` skill
|
|
122
|
+
- **401 / token 过期** — 走 `auth login --no-wait --force` split-flow 重登
|
|
123
|
+
- **`from 与 to 不能为空`** — 没传 `--visit-id` 时必须给时间窗
|
|
124
|
+
- **`to 必须晚于 from`** — 时间窗方向反了
|
|
125
|
+
- **`total: 0`** — 窗口内没有已完成分析的来访总结,或当前用户授权范围内无匹配
|
|
126
|
+
- **想看录音原文 / 列来访** — 录音转录走 `wangxiaobao-audio-query`;来访列表 + 录音走 `wangxiaobao-visit-query`
|
package/dist/visit-DoeECi8w.mjs
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { defineCommand } from "citty";
|
|
2
|
-
//#region src/commands/visit/index.ts
|
|
3
|
-
var visit_default = defineCommand({
|
|
4
|
-
meta: {
|
|
5
|
-
name: "visit",
|
|
6
|
-
description: "客户来访分页查询"
|
|
7
|
-
},
|
|
8
|
-
subCommands: { list: () => import("./list-CXquxzex.mjs").then((m) => m.default) }
|
|
9
|
-
});
|
|
10
|
-
//#endregion
|
|
11
|
-
export { visit_default as default };
|