@yosai/cli 0.0.0-stage → 0.2.1-test.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +66 -2
- package/dist/cli.js +188 -0
- package/dist/commands/context.js +6 -0
- package/dist/commands/docs-download.js +85 -0
- package/dist/commands/doctor.js +102 -0
- package/dist/commands/domain.js +16 -0
- package/dist/commands/index.js +10 -0
- package/dist/commands/kb-upload.js +210 -0
- package/dist/commands/kb.js +165 -0
- package/dist/commands/login.js +35 -0
- package/dist/commands/ping.js +40 -0
- package/dist/commands/skill.js +22 -0
- package/dist/commands/tool.js +129 -0
- package/dist/commands/update.js +73 -0
- package/dist/commands/version.js +44 -0
- package/dist/config.js +55 -0
- package/dist/domain-commands.js +477 -0
- package/dist/domain-executor.js +257 -0
- package/dist/endpoints.js +1 -0
- package/dist/errors.js +37 -0
- package/dist/index.js +5 -0
- package/dist/npm-meta.js +96 -0
- package/dist/openapis-client.js +112 -0
- package/dist/output.js +21 -0
- package/dist/prompt.js +40 -0
- package/dist/skill-sync.js +34 -0
- package/dist/skills/yos/SKILL.md +86 -0
- package/dist/skills/yos-install/SKILL.md +162 -0
- package/dist/skills/yos-kb/SKILL.md +388 -0
- package/dist/skills/yos-retrieval/SKILL.md +244 -0
- package/dist/skills/yos-retrieval/references/examples.md +152 -0
- package/dist/skills/yos-shared/SKILL.md +185 -0
- package/dist/skills/yos-support/SKILL.md +141 -0
- package/dist/skills/yos-transcript/SKILL.md +92 -0
- package/dist/tool-domains.js +38 -0
- package/dist/version-state.js +30 -0
- package/package.json +30 -4
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { register } from '../cli.js';
|
|
2
|
+
import { loadConfig } from '../config.js';
|
|
3
|
+
import { BusinessError } from '../errors.js';
|
|
4
|
+
import { compareVersions, detectGlobalInstall, fetchLatestVersion, PUBLIC_REGISTRY, readPackageMeta, runNpm } from '../npm-meta.js';
|
|
5
|
+
import { print, printJson } from '../output.js';
|
|
6
|
+
import { installSkillsTo } from '../skill-sync.js';
|
|
7
|
+
import { saveVersionState } from '../version-state.js';
|
|
8
|
+
register({
|
|
9
|
+
name: 'update',
|
|
10
|
+
description: '检查并升级 CLI 到 npmjs 最新版(升级后自动重同步 Skill)',
|
|
11
|
+
usage: 'yos update [--check] [--json]',
|
|
12
|
+
group: '基础',
|
|
13
|
+
risk: 'write',
|
|
14
|
+
options: { check: { type: 'boolean' }, json: { type: 'boolean' } },
|
|
15
|
+
paramNotes: [
|
|
16
|
+
['--check', '只检查是否有新版本,不安装、不写入状态'],
|
|
17
|
+
['--json', '结构化输出(仅 --check 生效)'],
|
|
18
|
+
],
|
|
19
|
+
async run({ flags }) {
|
|
20
|
+
const meta = readPackageMeta();
|
|
21
|
+
if (!meta) {
|
|
22
|
+
throw new BusinessError('无法确定包名(未找到 package.json)', '请通过 npm 全局安装后重试');
|
|
23
|
+
}
|
|
24
|
+
const latest = await fetchLatestVersion(meta.name);
|
|
25
|
+
const outdated = compareVersions(meta.version, latest) < 0;
|
|
26
|
+
if (flags.check) {
|
|
27
|
+
if (flags.json) {
|
|
28
|
+
printJson({ version: meta.version, latest, outdated });
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
print(outdated
|
|
32
|
+
? `当前 ${meta.version},最新 ${latest},执行 yos update 升级`
|
|
33
|
+
: `已是最新(${latest})`);
|
|
34
|
+
}
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (!outdated) {
|
|
38
|
+
syncSkills();
|
|
39
|
+
saveVersionState(meta.version);
|
|
40
|
+
print(`已是最新(${meta.version})`);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const shape = await detectGlobalInstall(meta);
|
|
44
|
+
if (!shape.global) {
|
|
45
|
+
print(`当前安装不在 npm 全局目录(${meta.dir}),不代跑升级`);
|
|
46
|
+
throw new BusinessError('非全局安装,已跳过自动升级', `手动升级:npm install -g ${meta.name}@latest --registry=${PUBLIC_REGISTRY};或先 npm uninstall -g ${meta.name} 再全局安装`);
|
|
47
|
+
}
|
|
48
|
+
const install = await runNpm(['install', '-g', `${meta.name}@latest`, `--registry=${PUBLIC_REGISTRY}`]);
|
|
49
|
+
if (!install.ok) {
|
|
50
|
+
const output = `${install.stderr}\n${install.stdout}`;
|
|
51
|
+
if (/EACCES|EPERM|permission denied/i.test(output)) {
|
|
52
|
+
throw new BusinessError('npm 全局目录没有写权限', '把 npm 前缀改到用户目录后重试(npm config set prefix ~/.npm-global 并把其 bin 加入 PATH),不要 sudo npm install -g');
|
|
53
|
+
}
|
|
54
|
+
throw new BusinessError(`npm install -g ${meta.name}@latest 失败:${firstLine(install.stderr) || firstLine(install.stdout) || '无输出'}`);
|
|
55
|
+
}
|
|
56
|
+
syncSkills();
|
|
57
|
+
saveVersionState(latest);
|
|
58
|
+
print(`已升级 ${meta.version} → ${latest}`);
|
|
59
|
+
print('提示:重启 Agent 工具以加载刷新后的 Skill');
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
function syncSkills() {
|
|
63
|
+
const dirs = loadConfig()?.installedSkillDirs ?? [];
|
|
64
|
+
if (dirs.length === 0) {
|
|
65
|
+
print('未记录 Skill 安装目录,跳过 Skill 同步(需要时执行 yos skill install)');
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
installSkillsTo(dirs);
|
|
69
|
+
print(`已重同步 Skill:${dirs.join(', ')}`);
|
|
70
|
+
}
|
|
71
|
+
function firstLine(text) {
|
|
72
|
+
return text.split(/\r?\n/)[0]?.trim() ?? '';
|
|
73
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { register } from '../cli.js';
|
|
2
|
+
import { loadConfig, resolveEndpoint } from '../config.js';
|
|
3
|
+
import { BusinessError } from '../errors.js';
|
|
4
|
+
import { compareVersions, detectGlobalInstall, fetchLatestVersion, readPackageMeta } from '../npm-meta.js';
|
|
5
|
+
import { print, printJson } from '../output.js';
|
|
6
|
+
register({
|
|
7
|
+
name: 'version',
|
|
8
|
+
description: '显示 CLI 版本(--check 比对 npmjs 最新版)',
|
|
9
|
+
usage: 'yos version [--json] [--check]',
|
|
10
|
+
group: '基础',
|
|
11
|
+
risk: 'read',
|
|
12
|
+
options: { json: { type: 'boolean' }, check: { type: 'boolean' } },
|
|
13
|
+
paramNotes: [
|
|
14
|
+
['--check', '与 npmjs 最新版本比对是否可升级(只读,不写入任何状态)'],
|
|
15
|
+
['--json', '结构化输出'],
|
|
16
|
+
],
|
|
17
|
+
async run({ flags }) {
|
|
18
|
+
const meta = readPackageMeta();
|
|
19
|
+
const version = meta?.version ?? 'unknown';
|
|
20
|
+
const endpoint = resolveEndpoint(loadConfig());
|
|
21
|
+
if (!flags.check) {
|
|
22
|
+
if (flags.json) {
|
|
23
|
+
const installedGlobally = meta ? (await detectGlobalInstall(meta)).global : false;
|
|
24
|
+
printJson({ version, installedGlobally, endpoint });
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
print(`yos CLI ${version}`);
|
|
28
|
+
}
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (!meta) {
|
|
32
|
+
throw new BusinessError('无法确定包名(未找到 package.json)', '请通过 npm 全局安装后重试');
|
|
33
|
+
}
|
|
34
|
+
const latest = await fetchLatestVersion(meta.name);
|
|
35
|
+
const outdated = compareVersions(meta.version, latest) < 0;
|
|
36
|
+
if (flags.json) {
|
|
37
|
+
printJson({ version, latest, outdated, installedGlobally: (await detectGlobalInstall(meta)).global, endpoint });
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
print(outdated
|
|
41
|
+
? `当前 ${meta.version},最新 ${latest},执行 yos update 升级`
|
|
42
|
+
: `已是最新(${latest})`);
|
|
43
|
+
},
|
|
44
|
+
});
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { DEFAULT_ENDPOINT } from './endpoints.js';
|
|
5
|
+
import { UsageError } from './errors.js';
|
|
6
|
+
export function configDir() {
|
|
7
|
+
return process.env.YOS_CONFIG_DIR ?? join(homedir(), '.config', 'yos');
|
|
8
|
+
}
|
|
9
|
+
export function configPath() {
|
|
10
|
+
return join(configDir(), 'config.json');
|
|
11
|
+
}
|
|
12
|
+
export function loadConfig() {
|
|
13
|
+
const path = configPath();
|
|
14
|
+
if (!existsSync(path)) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
return JSON.parse(readFileSync(path, 'utf8'));
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export function saveConfig(config) {
|
|
25
|
+
mkdirSync(configDir(), { recursive: true, mode: 0o700 });
|
|
26
|
+
writeFileSync(configPath(), `${JSON.stringify(config, null, 2)}\n`, { mode: 0o600 });
|
|
27
|
+
}
|
|
28
|
+
export function resolveKey(config) {
|
|
29
|
+
const fromEnv = process.env.YOS_API_KEY;
|
|
30
|
+
if (fromEnv) {
|
|
31
|
+
return fromEnv;
|
|
32
|
+
}
|
|
33
|
+
if (config?.apiKey) {
|
|
34
|
+
return config.apiKey;
|
|
35
|
+
}
|
|
36
|
+
throw new UsageError('未配置访问令牌', '请执行 `yos login` 或设置环境变量 YOS_API_KEY');
|
|
37
|
+
}
|
|
38
|
+
export function resolveEndpoint(config) {
|
|
39
|
+
const fromEnv = process.env.YOS_ENDPOINT;
|
|
40
|
+
if (fromEnv) {
|
|
41
|
+
return normalizeEndpoint(fromEnv);
|
|
42
|
+
}
|
|
43
|
+
return normalizeEndpoint(config?.endpoint ?? DEFAULT_ENDPOINT);
|
|
44
|
+
}
|
|
45
|
+
export function normalizeEndpoint(endpoint) {
|
|
46
|
+
return endpoint.replace(/\/+$/, '');
|
|
47
|
+
}
|
|
48
|
+
export function maskKey(key) {
|
|
49
|
+
return key.length <= 12 ? '****' : `${key.slice(0, 8)}****${key.slice(-4)}`;
|
|
50
|
+
}
|
|
51
|
+
export function updateConfig(patch) {
|
|
52
|
+
const merged = { endpoint: DEFAULT_ENDPOINT, ...loadConfig(), ...patch };
|
|
53
|
+
saveConfig(merged);
|
|
54
|
+
return merged;
|
|
55
|
+
}
|
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
import { assertAnyParam, assertDateRange, assertGrepOrder, assertNotBlank, assertNumericId, assertTextLength, normalizeReadItems, parseReadTarget, resolveContent, } from './domain-executor.js';
|
|
2
|
+
import { UsageError } from './errors.js';
|
|
3
|
+
import { parseToolJson } from './openapis-client.js';
|
|
4
|
+
import { print, renderRows } from './output.js';
|
|
5
|
+
export const DOMAIN_META = {
|
|
6
|
+
kb: { groupLabel: '知识库 kb', description: '知识库本体:列表 / 详情 / 更新 / 上传(新建知识库请到 YOS 客户端手动操作)' },
|
|
7
|
+
docs: { groupLabel: '文档 docs', description: '文档与节点:树 / 正文 / 下载 / 创建 / 更新 / 移动 / 删除 / 恢复' },
|
|
8
|
+
retrieve: { groupLabel: '检索 retrieve', description: 'cortex 检索原语:语义检索 / 定位 / 精读 / 配套 / 大纲' },
|
|
9
|
+
support: { groupLabel: '支持 support', description: '帮助手册 / 客户端升级 / 问题反馈' },
|
|
10
|
+
transcript: { groupLabel: '转写 transcript', description: '录音转写查询' },
|
|
11
|
+
};
|
|
12
|
+
export const DOMAIN_COMMANDS = [
|
|
13
|
+
{
|
|
14
|
+
name: 'kb list',
|
|
15
|
+
domain: 'kb',
|
|
16
|
+
tool: 'kb_list',
|
|
17
|
+
description: '列出知识库(缺省全部可见:我创建的 + 分享给我的)',
|
|
18
|
+
risk: 'read',
|
|
19
|
+
flags: [
|
|
20
|
+
{
|
|
21
|
+
flag: 'scope', param: 'range', kind: 'string',
|
|
22
|
+
description: '范围 created=我创建|shared=分享给我|all=全部可见(缺省 all)',
|
|
23
|
+
values: ['created', 'shared', 'all'],
|
|
24
|
+
},
|
|
25
|
+
{ flag: 'keyword', param: 'keyword', kind: 'string', description: '名称关键词(仅匹配库名,不搜正文)' },
|
|
26
|
+
{ flag: 'page', param: 'page', kind: 'number', description: '页码(缺省 1)', min: 1 },
|
|
27
|
+
{ flag: 'size', param: 'size', kind: 'number', description: '每页条数(缺省 10,上限 50)', min: 1, max: 50 },
|
|
28
|
+
],
|
|
29
|
+
render: (result) => {
|
|
30
|
+
const data = parseToolJson(result);
|
|
31
|
+
const records = data.records ?? [];
|
|
32
|
+
if (records.length === 0) {
|
|
33
|
+
print('(无知识库)');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
print(renderRows(records.map((r) => [
|
|
37
|
+
String(r.kbCode ?? r.kb_code ?? ''),
|
|
38
|
+
String(r.kbName ?? r.kb_name ?? r.name ?? ''),
|
|
39
|
+
])));
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'kb detail',
|
|
44
|
+
domain: 'kb',
|
|
45
|
+
tool: 'kb_detail',
|
|
46
|
+
description: '知识库详情',
|
|
47
|
+
risk: 'read',
|
|
48
|
+
positionals: [{ name: 'kb_code', param: 'kb_code', description: '知识库编码' }],
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: 'kb update',
|
|
52
|
+
domain: 'kb',
|
|
53
|
+
tool: 'kb_update',
|
|
54
|
+
description: '修改知识库名称或简介(至少传一个;需管理员及以上)',
|
|
55
|
+
risk: 'write',
|
|
56
|
+
positionals: [{ name: 'kb_code', param: 'kb_code', description: '知识库编码' }],
|
|
57
|
+
flags: [
|
|
58
|
+
{ flag: 'name', param: 'kb_name', kind: 'string', description: '新名称(≤24 字)' },
|
|
59
|
+
{ flag: 'description', param: 'description', kind: 'string', description: '新简介(≤80 字)' },
|
|
60
|
+
],
|
|
61
|
+
validateArgs: (args) => {
|
|
62
|
+
assertAnyParam(args, ['kb_name', 'description'], ['--name', '--description']);
|
|
63
|
+
assertTextLength(args.kb_name, 24, '知识库名称');
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: 'docs tree',
|
|
68
|
+
domain: 'docs',
|
|
69
|
+
tool: 'docs_tree',
|
|
70
|
+
description: '知识库目录树(文件夹/文档层级,不含正文)',
|
|
71
|
+
risk: 'read',
|
|
72
|
+
positionals: [{ name: 'kb_code', param: 'kb_code', description: '知识库编码' }],
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: 'docs content',
|
|
76
|
+
domain: 'docs',
|
|
77
|
+
tool: 'docs_content',
|
|
78
|
+
description: '读取文档标题与正文(上传文件类型无内联正文)',
|
|
79
|
+
risk: 'read',
|
|
80
|
+
positionals: [{ name: 'node_code', param: 'node_code', description: '文档节点编码' }],
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
name: 'docs count',
|
|
84
|
+
domain: 'docs',
|
|
85
|
+
tool: 'docs_count',
|
|
86
|
+
description: '统计删除影响范围(文档=1,文件夹=全部子孙数)',
|
|
87
|
+
risk: 'read',
|
|
88
|
+
positionals: [{
|
|
89
|
+
name: 'node_code', param: 'node_code',
|
|
90
|
+
description: '节点编码(文件夹或文档)',
|
|
91
|
+
}],
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: 'docs mkdir',
|
|
95
|
+
domain: 'docs',
|
|
96
|
+
tool: 'docs_mkdir',
|
|
97
|
+
description: '创建文件夹(需编辑者及以上权限)',
|
|
98
|
+
risk: 'write',
|
|
99
|
+
positionals: [{ name: '文件夹名', param: 'folder_name', description: '新建文件夹名称' }],
|
|
100
|
+
flags: [
|
|
101
|
+
{ flag: 'kb', param: 'kb_code', kind: 'string', description: '知识库编码(未传 --parent 时必填)' },
|
|
102
|
+
{ flag: 'parent', param: 'parent_code', kind: 'string', description: '父文件夹编码(须为文件夹节点;缺省知识库根目录)' },
|
|
103
|
+
],
|
|
104
|
+
validateArgs: (args) => assertAnyParam(args, ['kb_code', 'parent_code'], ['--kb', '--parent']),
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: 'docs create',
|
|
108
|
+
domain: 'docs',
|
|
109
|
+
tool: 'docs_create',
|
|
110
|
+
description: '创建文档(正文经 --content 或 --file 提供)',
|
|
111
|
+
risk: 'write',
|
|
112
|
+
positionals: [{ name: '标题', param: 'title', description: '文档标题(≤128 字)' }],
|
|
113
|
+
flags: [
|
|
114
|
+
{ flag: 'kb', param: 'kb_code', kind: 'string', description: '知识库编码' },
|
|
115
|
+
{ flag: 'parent', param: 'parent_code', kind: 'string', description: '父文件夹编码(缺省知识库根目录;须为文件夹节点)' },
|
|
116
|
+
{
|
|
117
|
+
flag: 'type', param: 'doc_type', kind: 'string',
|
|
118
|
+
description: '文档类型(缺省 md):md=Markdown 文本 / cloud=云文档 / sheet=表格;'
|
|
119
|
+
+ 'cloud 与 sheet 的正文须为对应草稿 JSON,一般场景一律用 md',
|
|
120
|
+
values: ['md', 'cloud', 'sheet'],
|
|
121
|
+
},
|
|
122
|
+
{ flag: 'content', param: 'content', kind: 'string', description: '正文文本(与 --file 二选一)' },
|
|
123
|
+
{ flag: 'file', param: 'content', kind: 'string', description: '正文文件路径(UTF-8,与 --content 二选一)' },
|
|
124
|
+
],
|
|
125
|
+
buildArgs: (context) => {
|
|
126
|
+
const title = context.positionals[0];
|
|
127
|
+
if (!title) {
|
|
128
|
+
throw new UsageError('缺少参数 <标题>', '用法: yos docs create <标题> --kb <code> (--content <文本> | --file <路径>)');
|
|
129
|
+
}
|
|
130
|
+
const args = {
|
|
131
|
+
title,
|
|
132
|
+
content: resolveContent(context.flags, true),
|
|
133
|
+
};
|
|
134
|
+
if (context.flags.kb) {
|
|
135
|
+
args.kb_code = context.flags.kb;
|
|
136
|
+
}
|
|
137
|
+
if (context.flags.parent) {
|
|
138
|
+
args.parent_code = context.flags.parent;
|
|
139
|
+
}
|
|
140
|
+
if (context.flags.type) {
|
|
141
|
+
args.doc_type = context.flags.type;
|
|
142
|
+
}
|
|
143
|
+
return args;
|
|
144
|
+
},
|
|
145
|
+
validateArgs: (args) => assertAnyParam(args, ['kb_code', 'parent_code'], ['--kb', '--parent']),
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
name: 'docs update',
|
|
149
|
+
domain: 'docs',
|
|
150
|
+
tool: 'docs_update',
|
|
151
|
+
description: '更新文档标题/正文/描述(正文为整体覆盖;需编辑者及以上权限)',
|
|
152
|
+
risk: 'write',
|
|
153
|
+
positionals: [{ name: 'node_code', param: 'node_code', description: '文档节点编码' }],
|
|
154
|
+
flags: [
|
|
155
|
+
{ flag: 'title', param: 'title', kind: 'string', description: '新标题' },
|
|
156
|
+
{ flag: 'content', param: 'content', kind: 'string', description: '新正文,整体覆盖原正文(与 --file 二选一)' },
|
|
157
|
+
{ flag: 'file', param: 'content', kind: 'string', description: '新正文文件路径,整体覆盖原正文(与 --content 二选一)' },
|
|
158
|
+
{ flag: 'description', param: 'description', kind: 'string', description: '新简介(≤100 字)' },
|
|
159
|
+
],
|
|
160
|
+
buildArgs: (context) => {
|
|
161
|
+
const nodeCode = context.positionals[0];
|
|
162
|
+
if (!nodeCode) {
|
|
163
|
+
throw new UsageError('缺少参数 <node_code>', '用法: yos docs update <node_code> [--title <新标题>] [--content <文本> | --file <路径>]');
|
|
164
|
+
}
|
|
165
|
+
const args = { node_code: nodeCode };
|
|
166
|
+
if (context.flags.title) {
|
|
167
|
+
args.title = context.flags.title;
|
|
168
|
+
}
|
|
169
|
+
const content = resolveContent(context.flags, false);
|
|
170
|
+
if (content !== undefined) {
|
|
171
|
+
args.content = content;
|
|
172
|
+
}
|
|
173
|
+
if (context.flags.description) {
|
|
174
|
+
args.description = context.flags.description;
|
|
175
|
+
}
|
|
176
|
+
return args;
|
|
177
|
+
},
|
|
178
|
+
validateArgs: (args) => assertAnyParam(args, ['title', 'content', 'description'], ['--title', '--content/--file', '--description']),
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
name: 'docs rename',
|
|
182
|
+
domain: 'docs',
|
|
183
|
+
tool: 'docs_rename',
|
|
184
|
+
description: '重命名文件夹(仅文件夹)',
|
|
185
|
+
risk: 'write',
|
|
186
|
+
positionals: [
|
|
187
|
+
{ name: 'node_code', param: 'node_code', description: '文件夹节点编码' },
|
|
188
|
+
{ name: '新名称', param: 'folder_name', description: '新文件夹名称' },
|
|
189
|
+
],
|
|
190
|
+
flags: [{ flag: 'description', param: 'description', kind: 'string', description: '新描述(可空)' }],
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
name: 'docs move',
|
|
194
|
+
domain: 'docs',
|
|
195
|
+
tool: 'docs_move',
|
|
196
|
+
description: '移动节点(--parent 缺省=移动至根目录;需管理员及以上)',
|
|
197
|
+
risk: 'write',
|
|
198
|
+
positionals: [{
|
|
199
|
+
name: 'node_code', param: 'node_code',
|
|
200
|
+
description: '待移动节点编码(文件夹或文档)',
|
|
201
|
+
}],
|
|
202
|
+
flags: [
|
|
203
|
+
{ flag: 'parent', param: 'parent_code', kind: 'string', description: '目标父节点编码(必须是文件夹节点;缺省知识库根目录)' },
|
|
204
|
+
{ flag: 'prev', param: 'prev_node_code', kind: 'string', description: '目标位置前一个相邻节点编码(控制排序,可空)' },
|
|
205
|
+
],
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
name: 'docs delete',
|
|
209
|
+
domain: 'docs',
|
|
210
|
+
tool: 'docs_delete',
|
|
211
|
+
description: '删除节点(级联进入回收站,90 天内可恢复)',
|
|
212
|
+
risk: 'danger',
|
|
213
|
+
positionals: [{
|
|
214
|
+
name: 'node_code', param: 'node_code',
|
|
215
|
+
description: '节点编码(文件夹或文档)',
|
|
216
|
+
}],
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
name: 'docs restore',
|
|
220
|
+
domain: 'docs',
|
|
221
|
+
tool: 'docs_restore',
|
|
222
|
+
description: '从回收站恢复节点(≤100 个;文件夹与其同批次子文件整组恢复)',
|
|
223
|
+
risk: 'write',
|
|
224
|
+
positionals: [{
|
|
225
|
+
name: 'node_code', param: 'node_codes', variadic: true,
|
|
226
|
+
description: '待恢复节点编码,可传多个(单次 ≤100 个)',
|
|
227
|
+
}],
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
name: 'retrieve search',
|
|
231
|
+
domain: 'retrieve',
|
|
232
|
+
tool: 'retrieve_search',
|
|
233
|
+
description: '跨库语义检索(时间表达由服务端解析)',
|
|
234
|
+
risk: 'read',
|
|
235
|
+
positionals: [{
|
|
236
|
+
name: 'query', param: 'query', variadic: true, kind: 'space-join',
|
|
237
|
+
description: '检索词,可含空格(多个词按空格拼为一句)',
|
|
238
|
+
}],
|
|
239
|
+
flags: [
|
|
240
|
+
{ flag: 'kb', param: 'kb_ids', kind: 'string', multiple: true, description: '限定知识库编码(可重复,1~10 个;缺省全部可见库)' },
|
|
241
|
+
{ flag: 'dir', param: 'dirs', kind: 'string', multiple: true, description: '限定目录节点编码(可重复)' },
|
|
242
|
+
{
|
|
243
|
+
flag: 'top-k', param: 'top_k', kind: 'number', min: 1, max: 25,
|
|
244
|
+
description: '召回条数(缺省 10,上限 25);结果按 score 降序,score 低表示相关度低,不代表一定相关',
|
|
245
|
+
},
|
|
246
|
+
{ flag: 'entity', param: 'entity_keywords', kind: 'string', multiple: true, description: '图谱实体关键词(可重复)' },
|
|
247
|
+
{ flag: 'topic', param: 'topic_keywords', kind: 'string', multiple: true, description: '图谱主题关键词(可重复)' },
|
|
248
|
+
{ flag: 'type', param: 'content_types', kind: 'string', multiple: true, description: '内容类型(可重复)' },
|
|
249
|
+
{
|
|
250
|
+
flag: 'labels', param: 'labels', kind: 'string',
|
|
251
|
+
description: '业务标签 JSON 对象,原样透传,如 \'{"部门":["风控"]}\'(维度间 AND、维度内 OR)',
|
|
252
|
+
},
|
|
253
|
+
{ flag: 'occurred-after', param: 'occurred_after', kind: 'string', description: '事件时间下限(自然语言,如 2026-01-01 / 上季度)' },
|
|
254
|
+
{ flag: 'occurred-before', param: 'occurred_before', kind: 'string', description: '事件时间上限(自然语言)' },
|
|
255
|
+
{ flag: 'effective-after', param: 'effective_after', kind: 'string', description: '生效日期下限(自然语言)' },
|
|
256
|
+
{ flag: 'effective-before', param: 'effective_before', kind: 'string', description: '生效日期上限(自然语言)' },
|
|
257
|
+
{ flag: 'include-inactive', param: 'include_inactive', kind: 'boolean', description: '纳入已失效文档' },
|
|
258
|
+
],
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
name: 'retrieve grep',
|
|
262
|
+
domain: 'retrieve',
|
|
263
|
+
tool: 'retrieve_grep',
|
|
264
|
+
description: '正则精确定位(文号/编号等一字不差的串)',
|
|
265
|
+
risk: 'read',
|
|
266
|
+
positionals: [
|
|
267
|
+
{
|
|
268
|
+
name: 'target', param: 'target',
|
|
269
|
+
description: '目标 URN:文档级 cortex://kb/{kb_code}/doc/{node_code} 或库级 cortex://kb/{kb_code}',
|
|
270
|
+
},
|
|
271
|
+
{ name: 'pattern', param: 'pattern', description: '正则表达式(在 target 之后,与 Unix grep 的参数顺序相反)' },
|
|
272
|
+
],
|
|
273
|
+
flags: [
|
|
274
|
+
{ flag: 'context', param: 'context', kind: 'number', min: 0, description: '命中行上下各 N 行' },
|
|
275
|
+
{ flag: 'before', param: 'before', kind: 'number', min: 0, description: '命中行前 N 行' },
|
|
276
|
+
{ flag: 'after', param: 'after', kind: 'number', min: 0, description: '命中行后 N 行' },
|
|
277
|
+
{ flag: 'ignore-case', param: 'case_insensitive', kind: 'boolean', description: '忽略大小写' },
|
|
278
|
+
{
|
|
279
|
+
flag: 'mode', param: 'output_mode', kind: 'string', values: ['content', 'count'],
|
|
280
|
+
description: '输出模式(缺省 content):content=命中行+上下文 / count=仅命中总数(count 只支持文档级 target)',
|
|
281
|
+
},
|
|
282
|
+
{ flag: 'offset', param: 'offset', kind: 'number', min: 0, description: '命中结果分页起点(从 0 开始)' },
|
|
283
|
+
{ flag: 'limit', param: 'limit', kind: 'number', min: 1, description: '返回命中条数' },
|
|
284
|
+
],
|
|
285
|
+
validateArgs: (args) => assertGrepOrder(args.target, args.pattern),
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
name: 'retrieve read',
|
|
289
|
+
domain: 'retrieve',
|
|
290
|
+
tool: 'retrieve_read',
|
|
291
|
+
description: '读原文(<target>:起-止 区间简写,1~10 项)',
|
|
292
|
+
risk: 'read',
|
|
293
|
+
positionals: [{
|
|
294
|
+
name: 'target[:起-止]', param: 'items', variadic: true,
|
|
295
|
+
description: '目标 URN,可带 :起-止 行号区间(含两端,缺省 1-200),如 '
|
|
296
|
+
+ 'cortex://kb/KBxxxx/doc/NDxxxx:10-60;单次最多 10 项',
|
|
297
|
+
}],
|
|
298
|
+
flags: [{
|
|
299
|
+
flag: 'items', param: 'items', kind: 'string',
|
|
300
|
+
description: 'JSON 数组(与位置参数互斥),每项 {"target":"cortex://...","offset":1,"limit":200};'
|
|
301
|
+
+ 'target 亦支持 :起-止 简写',
|
|
302
|
+
}],
|
|
303
|
+
buildArgs: (context) => {
|
|
304
|
+
const itemsFlag = context.flags.items;
|
|
305
|
+
if (itemsFlag) {
|
|
306
|
+
if (context.positionals.length > 0) {
|
|
307
|
+
throw new UsageError('--items 与位置参数互斥', "二选一:位置参数 <target>:起-止 或 --items '[{...}]'");
|
|
308
|
+
}
|
|
309
|
+
return { items: normalizeReadItems(String(itemsFlag)) };
|
|
310
|
+
}
|
|
311
|
+
if (context.positionals.length === 0) {
|
|
312
|
+
throw new UsageError('缺少 target', "用法: yos retrieve read <target>[:起-止] ... 或 --items '[{...}]'");
|
|
313
|
+
}
|
|
314
|
+
if (context.positionals.length > 10) {
|
|
315
|
+
throw new UsageError(`单次最多读取 10 个区间(实际 ${context.positionals.length} 个)`, '拆分为多次调用');
|
|
316
|
+
}
|
|
317
|
+
return { items: JSON.stringify(context.positionals.map(parseReadTarget)) };
|
|
318
|
+
},
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
name: 'retrieve neighbors',
|
|
322
|
+
domain: 'retrieve',
|
|
323
|
+
tool: 'retrieve_neighbors',
|
|
324
|
+
description: '查找配套文档(kind: related=按内容找相关 / sibling=同目录兄弟)',
|
|
325
|
+
risk: 'read',
|
|
326
|
+
positionals: [{
|
|
327
|
+
name: 'target', param: 'target', validate: 'urn',
|
|
328
|
+
description: '文档级 URN:cortex://kb/{kb_code}/doc/{node_code}',
|
|
329
|
+
}],
|
|
330
|
+
flags: [
|
|
331
|
+
{
|
|
332
|
+
flag: 'kind', param: 'kind', kind: 'string', required: true, values: ['related', 'sibling'],
|
|
333
|
+
description: 'related=按正文内容找最相关文档(跨目录,多数场景选它)/ sibling=同目录兄弟文档',
|
|
334
|
+
},
|
|
335
|
+
{ flag: 'limit', param: 'limit', kind: 'number', min: 1, description: '返回条数' },
|
|
336
|
+
{ flag: 'include-inactive', param: 'include_inactive', kind: 'boolean', description: '纳入已失效文档' },
|
|
337
|
+
],
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
name: 'retrieve outline',
|
|
341
|
+
domain: 'retrieve',
|
|
342
|
+
tool: 'retrieve_outline',
|
|
343
|
+
description: '库级=文档清单 / 文档级=章节树',
|
|
344
|
+
risk: 'read',
|
|
345
|
+
positionals: [{
|
|
346
|
+
name: 'target', param: 'target', validate: 'urn',
|
|
347
|
+
description: '目标 URN:库级 cortex://kb/{kb_code} 返回文档清单(含行数);'
|
|
348
|
+
+ '文档级 cortex://kb/{kb_code}/doc/{node_code} 返回章节树',
|
|
349
|
+
}],
|
|
350
|
+
flags: [
|
|
351
|
+
{ flag: 'depth', param: 'depth', kind: 'number', min: 1, max: 3, description: '章节树展开深度(缺省 2,上限 3;仅文档级 target 生效)' },
|
|
352
|
+
{ flag: 'expand', param: 'expand', kind: 'string', multiple: true, description: '展开的章节编号(可重复;命中的子树全量展开,不受 --depth 限制)' },
|
|
353
|
+
{
|
|
354
|
+
flag: 'labels', param: 'labels', kind: 'string',
|
|
355
|
+
description: '业务标签 JSON 对象,原样透传,如 \'{"部门":["风控"]}\'(维度间 AND、维度内 OR)',
|
|
356
|
+
},
|
|
357
|
+
{ flag: 'occurred-after', param: 'occurred_after', kind: 'string', description: '事件时间下限(自然语言)' },
|
|
358
|
+
{ flag: 'occurred-before', param: 'occurred_before', kind: 'string', description: '事件时间上限(自然语言)' },
|
|
359
|
+
{ flag: 'effective-after', param: 'effective_after', kind: 'string', description: '生效日期下限(自然语言)' },
|
|
360
|
+
{ flag: 'effective-before', param: 'effective_before', kind: 'string', description: '生效日期上限(自然语言)' },
|
|
361
|
+
],
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
name: 'support manual',
|
|
365
|
+
domain: 'support',
|
|
366
|
+
tool: 'support_manual',
|
|
367
|
+
description: '帮助手册目录树(先看结构再读取或检索)',
|
|
368
|
+
risk: 'read',
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
name: 'support manual-read',
|
|
372
|
+
domain: 'support',
|
|
373
|
+
tool: 'support_manual_read',
|
|
374
|
+
description: '按节点 ID 读帮助手册文章正文',
|
|
375
|
+
risk: 'read',
|
|
376
|
+
positionals: [{
|
|
377
|
+
name: 'node_id', param: 'node_id',
|
|
378
|
+
description: '手册节点 ID(FOLDER 节点无正文)',
|
|
379
|
+
}],
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
name: 'support manual-search',
|
|
383
|
+
domain: 'support',
|
|
384
|
+
tool: 'support_manual_search',
|
|
385
|
+
description: '关键词检索帮助手册(标题/正文命中)',
|
|
386
|
+
risk: 'read',
|
|
387
|
+
positionals: [{ name: 'keyword', param: 'keyword', description: '检索关键词(匹配手册标题与正文)' }],
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
name: 'support upgrade',
|
|
391
|
+
domain: 'support',
|
|
392
|
+
tool: 'support_upgrade',
|
|
393
|
+
description: '查询指定平台最新客户端版本(灰度仅白名单可见)',
|
|
394
|
+
risk: 'read',
|
|
395
|
+
flags: [
|
|
396
|
+
{
|
|
397
|
+
flag: 'platform', param: 'platform', kind: 'string', required: true,
|
|
398
|
+
description: 'WIN=Windows / MAC_X64=macOS Intel / MAC_ARM64=macOS Apple Silicon',
|
|
399
|
+
values: ['WIN', 'MAC_X64', 'MAC_ARM64'],
|
|
400
|
+
},
|
|
401
|
+
],
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
name: 'support upgrade-log',
|
|
405
|
+
domain: 'support',
|
|
406
|
+
tool: 'support_upgrade_log',
|
|
407
|
+
description: '客户端升级记录(含公告全文)',
|
|
408
|
+
risk: 'read',
|
|
409
|
+
flags: [
|
|
410
|
+
{
|
|
411
|
+
flag: 'platform', param: 'platform', kind: 'string',
|
|
412
|
+
description: '平台过滤(缺省全部):WIN / MAC_X64 / MAC_ARM64',
|
|
413
|
+
values: ['WIN', 'MAC_X64', 'MAC_ARM64'],
|
|
414
|
+
},
|
|
415
|
+
{ flag: 'start', param: 'start_date', kind: 'string', description: '发布日期下限(yyyy-MM-dd)' },
|
|
416
|
+
{ flag: 'end', param: 'end_date', kind: 'string', description: '发布日期上限(yyyy-MM-dd)' },
|
|
417
|
+
{ flag: 'page', param: 'page', kind: 'number', description: '页码(缺省 1)', min: 1 },
|
|
418
|
+
{ flag: 'size', param: 'size', kind: 'number', description: '每页条数(缺省 10,上限 50)', min: 1, max: 50 },
|
|
419
|
+
],
|
|
420
|
+
validateArgs: (args) => assertDateRange(args.start_date, args.end_date, 'start', 'end'),
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
name: 'support feedback',
|
|
424
|
+
domain: 'support',
|
|
425
|
+
tool: 'support_feedback',
|
|
426
|
+
description: '提交反馈(自动关联当前用户与所属企业,≤2000 字)',
|
|
427
|
+
risk: 'write',
|
|
428
|
+
positionals: [{
|
|
429
|
+
name: '内容', param: 'content', variadic: true, kind: 'space-join',
|
|
430
|
+
description: '反馈正文(≤2000 字,可含空格);不支持附件,提交后无法查询进度或撤回',
|
|
431
|
+
}],
|
|
432
|
+
validateArgs: (args) => {
|
|
433
|
+
assertNotBlank(args.content, '反馈内容', '用法: yos support feedback <内容...>');
|
|
434
|
+
assertTextLength(args.content, 2000, '反馈内容');
|
|
435
|
+
},
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
name: 'transcript list',
|
|
439
|
+
domain: 'transcript',
|
|
440
|
+
tool: 'transcript_list',
|
|
441
|
+
description: '列出我的转写记录(自建与他人分享,恒排除失败状态)',
|
|
442
|
+
risk: 'read',
|
|
443
|
+
flags: [
|
|
444
|
+
{ flag: 'page', param: 'page', kind: 'number', description: '页码(缺省 1)', min: 1 },
|
|
445
|
+
{ flag: 'size', param: 'size', kind: 'number', description: '每页条数(缺省 10,上限 50)', min: 1, max: 50 },
|
|
446
|
+
{
|
|
447
|
+
flag: 'status', param: 'status', kind: 'string',
|
|
448
|
+
description: '状态过滤:recording=录制中/转写中 / recorded=待总结 / summarizing=总结中 / summarized=总结完成'
|
|
449
|
+
+ '(failed 恒被排除,不可作为过滤值)',
|
|
450
|
+
values: ['recording', 'recorded', 'summarizing', 'summarized'],
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
flag: 'relation', param: 'relation_type', kind: 'string', values: ['owner', 'shared', 'all'],
|
|
454
|
+
description: '归属过滤(缺省 all):owner=我创建 / shared=他人分享给我',
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
flag: 'keyword', param: 'keyword', kind: 'string',
|
|
458
|
+
description: '关键词:匹配创建人姓名与主题(模糊)或转写编码(全等);不检索纪要与逐字稿',
|
|
459
|
+
},
|
|
460
|
+
{ flag: 'start', param: 'start_date', kind: 'string', description: '开始日期(yyyy-MM-dd,含当日)' },
|
|
461
|
+
{ flag: 'end', param: 'end_date', kind: 'string', description: '结束日期(yyyy-MM-dd,含当日)' },
|
|
462
|
+
],
|
|
463
|
+
validateArgs: (args) => assertDateRange(args.start_date, args.end_date, 'start', 'end'),
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
name: 'transcript detail',
|
|
467
|
+
domain: 'transcript',
|
|
468
|
+
tool: 'transcript_detail',
|
|
469
|
+
description: '转写详情(含全文分段/纪要/思维导图,仅已完成可读)',
|
|
470
|
+
risk: 'read',
|
|
471
|
+
positionals: [{
|
|
472
|
+
name: 'transcription_user_id', param: 'transcription_user_id',
|
|
473
|
+
description: '转写归属记录 ID(数字,非 TT 开头的转写编码)',
|
|
474
|
+
}],
|
|
475
|
+
validateArgs: (args) => assertNumericId(args.transcription_user_id, '转写归属记录 ID', 'TT 开头的是转写编码,本命令需要对应的数字 ID'),
|
|
476
|
+
},
|
|
477
|
+
];
|