@yosai/cli 0.2.1-test.14 → 0.2.1-test.15
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 +2 -1
- package/dist/commands/doctor.js +21 -2
- package/dist/commands/login.js +10 -2
- package/dist/commands/skill.js +5 -2
- package/dist/commands/update.js +16 -6
- package/dist/skill-scope.js +111 -0
- package/dist/skill-sync.js +22 -5
- package/dist/skills/yos/SKILL.md +33 -1
- package/dist/skills/yos-retrieval/SKILL.md +4 -0
- package/dist/skills/yos-shared/SKILL.md +33 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -45,7 +45,7 @@ yos tool list # 底层工具通道(领域命令未覆盖
|
|
|
45
45
|
## 给 Agent 使用
|
|
46
46
|
|
|
47
47
|
```bash
|
|
48
|
-
yos skill install #
|
|
48
|
+
yos skill install # 按当前令牌权限安装内置 Skill(总入口 + 领域 + 安装引导)到 Claude Code / Cursor / Codex / Qoder / WorkBuddy 等技能目录
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
安装后重启 Agent 工具,即可用自然语言驱动(如「把这份报告上传到知识库」)。`yos` 为能力总入口(何时使用 / 能力地图 / 命令使用方式),Agent 据此路由到各领域细则;`yos-shared` 收录跨领域约定(输出解析、退出码契约、仍需自行校验内容的场景、安全纪律);`yos-install` 是自包含的安装配置引导,可单独下载到发布仓库供用户引导装机。
|
|
@@ -58,6 +58,7 @@ yos skill install # 安装 9 个内置 Skill(总入口 + 领域 + 安装
|
|
|
58
58
|
- 环境变量(均优先于配置文件,适合 CI/容器场景):`YOS_API_KEY` 访问令牌、`YOS_ENV` 服务环境(prod / test / dev)
|
|
59
59
|
- 版本检查:命令执行前会检查对应通道最新版(后台进程查询、结果缓存 10 分钟),落后时以 stderr 提示「请先执行 yos update 升级再继续任务」;升级通道自动跟随服务环境(测试环境跟 test 通道)。CLI 不静默安装,升级由用户或 Agent 按提示显式执行
|
|
60
60
|
- 服务环境(测试/开发用):`yos login --env test` 切到测试环境,`--env dev` 指向本机开发服务(http://localhost:8080)
|
|
61
|
+
- Skill 按令牌权限安装:`yos login` / `yos skill install` 从 `whoami` 取令牌 scope 并缓存,只安装有权限的技能(外部令牌仅 `yos`、`yos-shared`、`yos-install`、`yos-retrieval`),并按 scope 裁剪技能正文中无权限的段落;换令牌登录后自动重新同步,`yos doctor` 的「Skill 权限」项校验一致性。技能源文件用 `<!-- @scope a,b -->` / `<!-- @else -->` / `<!-- @end -->`(frontmatter 内用 `# @scope …` 注释形式)标记受限段落,新增技能须在 `src/skill-scope.ts` 登记所需 scope
|
|
61
62
|
- 托管模式(YOS 客户端内置 CLI 专用):`YOS_MANAGED=1` 时安装、升级、登录与 Skill 由客户端统一管理——不做版本检查与升级提示,拒绝 `update` / `install` / `login` / `skill install`,令牌只认客户端注入的 `YOS_API_KEY`(不读配置文件),`doctor` 跳过配置文件与 Skill 检查;客户端应同时以 `YOS_CONFIG_DIR` 指向自身私有目录,与用户自行安装的 CLI 配置隔离
|
|
62
63
|
|
|
63
64
|
## 故障排查
|
package/dist/commands/doctor.js
CHANGED
|
@@ -6,6 +6,8 @@ import { isManaged } from '../managed.js';
|
|
|
6
6
|
import { formatIdentity, OpenApisClient } from '../openapis-client.js';
|
|
7
7
|
import { print, printJson } from '../output.js';
|
|
8
8
|
import { readPackageMeta } from '../npm-meta.js';
|
|
9
|
+
import { describeScopes, isSkillAllowed } from '../skill-scope.js';
|
|
10
|
+
import { listInstalledSkills, listSourceSkills } from '../skill-sync.js';
|
|
9
11
|
import { loadVersionState } from '../version-state.js';
|
|
10
12
|
register({
|
|
11
13
|
name: 'doctor',
|
|
@@ -39,13 +41,18 @@ register({
|
|
|
39
41
|
checks.push({ name: '访问令牌', ok: false, detail: e.message });
|
|
40
42
|
}
|
|
41
43
|
let connectionFailure = null;
|
|
44
|
+
let identity = null;
|
|
42
45
|
if (!key) {
|
|
43
46
|
checks.push({ name: '服务连通', ok: false, detail: '未配置访问令牌,未验证(先执行 yos login)' });
|
|
44
47
|
}
|
|
45
48
|
else {
|
|
46
49
|
try {
|
|
47
|
-
|
|
48
|
-
checks.push({
|
|
50
|
+
identity = await new OpenApisClient(`${endpoint}/open-apis`, key).whoami();
|
|
51
|
+
checks.push({
|
|
52
|
+
name: '服务连通',
|
|
53
|
+
ok: true,
|
|
54
|
+
detail: `身份 ${formatIdentity(identity)},${describeScopes(identity.tokenType, identity.scopes ?? null)}`,
|
|
55
|
+
});
|
|
49
56
|
}
|
|
50
57
|
catch (e) {
|
|
51
58
|
const failure = e instanceof CliError ? e : new CliError(String(e), EXIT.BUSINESS);
|
|
@@ -76,6 +83,18 @@ register({
|
|
|
76
83
|
detail: skillSyncDetail(meta, state, skillDirs),
|
|
77
84
|
});
|
|
78
85
|
}
|
|
86
|
+
if (!managed && identity && skillDirs.length > 0) {
|
|
87
|
+
const scopes = identity.scopes ?? null;
|
|
88
|
+
const expected = listSourceSkills().filter((skill) => isSkillAllowed(skill, scopes));
|
|
89
|
+
const mismatched = skillDirs.filter((dir) => listInstalledSkills(dir).join(',') !== expected.join(','));
|
|
90
|
+
checks.push({
|
|
91
|
+
name: 'Skill 权限',
|
|
92
|
+
ok: mismatched.length === 0,
|
|
93
|
+
detail: mismatched.length === 0
|
|
94
|
+
? `与令牌权限一致(${expected.length} 个 Skill)`
|
|
95
|
+
: `${mismatched.length} 个目录的 Skill 与令牌权限不一致,执行 yos skill install`,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
79
98
|
if (flags.json) {
|
|
80
99
|
printJson({ checks });
|
|
81
100
|
}
|
package/dist/commands/login.js
CHANGED
|
@@ -5,6 +5,8 @@ import { UsageError } from '../errors.js';
|
|
|
5
5
|
import { formatIdentity, OpenApisClient } from '../openapis-client.js';
|
|
6
6
|
import { print } from '../output.js';
|
|
7
7
|
import { readHiddenLine } from '../prompt.js';
|
|
8
|
+
import { describeScopes } from '../skill-scope.js';
|
|
9
|
+
import { installSkillsTo } from '../skill-sync.js';
|
|
8
10
|
register({
|
|
9
11
|
name: 'login',
|
|
10
12
|
description: '配置访问令牌与服务环境(校验身份后保存)',
|
|
@@ -29,8 +31,14 @@ register({
|
|
|
29
31
|
throw new UsageError('令牌格式不正确(应为 40 位小写 hex)', '请在客户端「个人设置-访问令牌」页创建并复制完整令牌');
|
|
30
32
|
}
|
|
31
33
|
const identity = await new OpenApisClient(`${endpoint}/open-apis`, key).whoami();
|
|
32
|
-
saveConfig({ ...config, env, apiKey: key });
|
|
34
|
+
saveConfig({ ...config, env, apiKey: key, tokenType: identity.tokenType, scopes: identity.scopes });
|
|
33
35
|
const envNote = env === DEFAULT_ENV ? '' : `环境=${envLabel(env)},`;
|
|
34
|
-
|
|
36
|
+
const scopes = identity.scopes ?? null;
|
|
37
|
+
print(`已保存配置:${envNote}key=${maskKey(key)},身份 ${formatIdentity(identity)},${describeScopes(identity.tokenType, scopes)}`);
|
|
38
|
+
const skillDirs = config?.installedSkillDirs ?? [];
|
|
39
|
+
if (skillDirs.length > 0) {
|
|
40
|
+
const skills = installSkillsTo(skillDirs, scopes);
|
|
41
|
+
print(`已按新令牌权限重新同步 ${skills.length} 个 Skill,重启 Agent 工具后生效`);
|
|
42
|
+
}
|
|
35
43
|
},
|
|
36
44
|
});
|
package/dist/commands/skill.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { register } from '../cli.js';
|
|
2
2
|
import { UsageError } from '../errors.js';
|
|
3
3
|
import { print } from '../output.js';
|
|
4
|
+
import { loadConfig } from '../config.js';
|
|
5
|
+
import { describeScopes, resolveSkillScopes } from '../skill-scope.js';
|
|
4
6
|
import { detectSkillTargets, installSkillsTo } from '../skill-sync.js';
|
|
5
7
|
register({
|
|
6
8
|
name: 'skill install',
|
|
@@ -15,8 +17,9 @@ register({
|
|
|
15
17
|
if (targets.length === 0) {
|
|
16
18
|
throw new UsageError('未发现已安装的 Agent 技能目录', '请用 --target <dir> 指定(如 ~/.claude/skills)');
|
|
17
19
|
}
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
+
const scopes = await resolveSkillScopes();
|
|
21
|
+
const skills = installSkillsTo(targets, scopes);
|
|
22
|
+
print(`已安装 ${skills.length} 个 Skill(${describeScopes(loadConfig()?.tokenType, scopes)})到:\n${targets.join('\n')}`);
|
|
20
23
|
print('提示:重启 Agent 工具以确保 Skill 加载');
|
|
21
24
|
},
|
|
22
25
|
});
|
package/dist/commands/update.js
CHANGED
|
@@ -4,6 +4,7 @@ import { BusinessError } from '../errors.js';
|
|
|
4
4
|
import { ensureVersionExists, INSTALLABLE_VERSION, installGlobal } from '../npm-install.js';
|
|
5
5
|
import { compareVersions, detectGlobalInstall, fetchLatestVersion, PUBLIC_REGISTRY, readPackageMeta, resolveInstallPrefix } from '../npm-meta.js';
|
|
6
6
|
import { print, printJson } from '../output.js';
|
|
7
|
+
import { resolveSkillScopes } from '../skill-scope.js';
|
|
7
8
|
import { installSkillsTo } from '../skill-sync.js';
|
|
8
9
|
import { saveVersionState } from '../version-state.js';
|
|
9
10
|
register({
|
|
@@ -45,13 +46,13 @@ register({
|
|
|
45
46
|
return;
|
|
46
47
|
}
|
|
47
48
|
if (!outdated) {
|
|
48
|
-
syncSkills();
|
|
49
|
+
await syncSkills();
|
|
49
50
|
saveVersionState(meta.version);
|
|
50
51
|
print(`已是最新(${meta.version})`);
|
|
51
52
|
return;
|
|
52
53
|
}
|
|
53
54
|
await installGlobally(meta, `${meta.name}@${channel}`);
|
|
54
|
-
syncSkills();
|
|
55
|
+
await syncSkills();
|
|
55
56
|
saveVersionState(latest);
|
|
56
57
|
print(`已升级 ${meta.version} → ${latest}`);
|
|
57
58
|
print('提示:重启 Agent 工具以加载刷新后的 Skill');
|
|
@@ -62,14 +63,14 @@ async function installVersion(meta, version) {
|
|
|
62
63
|
throw new BusinessError(`版本格式非法:${version}`, '示例:0.2.0 或 0.2.1-test.9;安装通道最新版请直接执行 yos update');
|
|
63
64
|
}
|
|
64
65
|
if (compareVersions(version, meta.version) === 0) {
|
|
65
|
-
syncSkills();
|
|
66
|
+
await syncSkills();
|
|
66
67
|
saveVersionState(meta.version);
|
|
67
68
|
print(`已是指定版本(${version})`);
|
|
68
69
|
return;
|
|
69
70
|
}
|
|
70
71
|
await ensureVersionExists(meta.name, version);
|
|
71
72
|
await installGlobally(meta, `${meta.name}@${version}`);
|
|
72
|
-
syncSkills();
|
|
73
|
+
await syncSkills();
|
|
73
74
|
saveVersionState(version);
|
|
74
75
|
print(`${compareVersions(version, meta.version) > 0 ? '已升级' : '已回退'} ${meta.version} → ${version}`);
|
|
75
76
|
print('提示:重启 Agent 工具以加载刷新后的 Skill');
|
|
@@ -87,14 +88,23 @@ async function installGlobally(meta, spec) {
|
|
|
87
88
|
}
|
|
88
89
|
await installGlobal(spec);
|
|
89
90
|
}
|
|
90
|
-
function syncSkills() {
|
|
91
|
+
async function syncSkills() {
|
|
91
92
|
const dirs = loadConfig()?.installedSkillDirs ?? [];
|
|
92
93
|
if (dirs.length === 0) {
|
|
93
94
|
print('未记录 Skill 安装目录,跳过 Skill 同步(需要时执行 yos skill install)');
|
|
94
95
|
return;
|
|
95
96
|
}
|
|
97
|
+
let scopes;
|
|
96
98
|
try {
|
|
97
|
-
|
|
99
|
+
scopes = await resolveSkillScopes();
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
103
|
+
print(`无法确认令牌权限,跳过 Skill 同步(${reason}),恢复后执行 yos skill install`);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
try {
|
|
107
|
+
installSkillsTo(dirs, scopes);
|
|
98
108
|
}
|
|
99
109
|
catch (error) {
|
|
100
110
|
const reason = error instanceof Error ? error.message : String(error);
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { endpointOfEnv } from './endpoints.js';
|
|
2
|
+
import { AuthError, UsageError } from './errors.js';
|
|
3
|
+
import { loadConfig, resolveEnv, resolveKey, updateConfig } from './config.js';
|
|
4
|
+
import { OpenApisClient } from './openapis-client.js';
|
|
5
|
+
export const ALL_SCOPES = ['knowledge:retrieve', 'knowledge:manage', 'transcript:read', 'support'];
|
|
6
|
+
const SKILL_SCOPES = {
|
|
7
|
+
yos: null,
|
|
8
|
+
'yos-shared': null,
|
|
9
|
+
'yos-install': null,
|
|
10
|
+
'yos-retrieval': 'knowledge:retrieve',
|
|
11
|
+
'yos-knowledge': 'knowledge:manage',
|
|
12
|
+
'yos-doc': 'knowledge:manage',
|
|
13
|
+
'yos-sheet': 'knowledge:manage',
|
|
14
|
+
'yos-transcript': 'transcript:read',
|
|
15
|
+
'yos-support': 'support',
|
|
16
|
+
};
|
|
17
|
+
const SCOPE_LABEL = {
|
|
18
|
+
'knowledge:retrieve': '知识库检索',
|
|
19
|
+
'knowledge:manage': '知识库管理',
|
|
20
|
+
'transcript:read': '转写查询',
|
|
21
|
+
support: '帮助与支持',
|
|
22
|
+
};
|
|
23
|
+
const TOKEN_TYPE_LABEL = { EXTERNAL: '外部令牌', INTERNAL: '内置令牌' };
|
|
24
|
+
const BODY_MARKER = /^\s*<!--\s*@(scope|else|end)\b\s*(.*?)\s*-->\s*$/;
|
|
25
|
+
const FRONTMATTER_MARKER = /^\s*#\s*@(scope|else|end)\b\s*(.*?)\s*$/;
|
|
26
|
+
export function isSkillAllowed(skill, scopes) {
|
|
27
|
+
if (scopes === null) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
if (!(skill in SKILL_SCOPES)) {
|
|
31
|
+
return ALL_SCOPES.every((scope) => scopes.includes(scope));
|
|
32
|
+
}
|
|
33
|
+
const required = SKILL_SCOPES[skill];
|
|
34
|
+
return required === null || scopes.includes(required);
|
|
35
|
+
}
|
|
36
|
+
export function renderScoped(text, scopes) {
|
|
37
|
+
const lines = text.split('\n');
|
|
38
|
+
const output = [];
|
|
39
|
+
let inFrontmatter = lines[0]?.trim() === '---';
|
|
40
|
+
let block = null;
|
|
41
|
+
lines.forEach((line, index) => {
|
|
42
|
+
if (inFrontmatter && index > 0 && line.trim() === '---') {
|
|
43
|
+
inFrontmatter = false;
|
|
44
|
+
}
|
|
45
|
+
const matched = (inFrontmatter ? FRONTMATTER_MARKER : BODY_MARKER).exec(line);
|
|
46
|
+
if (matched) {
|
|
47
|
+
const [, kind, args] = matched;
|
|
48
|
+
if (kind === 'scope') {
|
|
49
|
+
if (block) {
|
|
50
|
+
throw new Error(`Skill 标记不支持嵌套(第 ${index + 1} 行)`);
|
|
51
|
+
}
|
|
52
|
+
const required = args.split(',').map((scope) => scope.trim()).filter(Boolean);
|
|
53
|
+
block = { satisfied: scopes === null || required.some((scope) => scopes.includes(scope)), inElse: false };
|
|
54
|
+
}
|
|
55
|
+
else if (!block) {
|
|
56
|
+
throw new Error(`Skill 标记 @${kind} 缺少对应的 @scope(第 ${index + 1} 行)`);
|
|
57
|
+
}
|
|
58
|
+
else if (kind === 'else') {
|
|
59
|
+
block.inElse = true;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
block = null;
|
|
63
|
+
}
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (block && block.inElse === block.satisfied) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
output.push(block?.inElse && inFrontmatter ? line.replace(/^(\s*)# /, '$1') : line);
|
|
70
|
+
});
|
|
71
|
+
if (block) {
|
|
72
|
+
throw new Error('Skill 标记 @scope 未闭合(缺少 @end)');
|
|
73
|
+
}
|
|
74
|
+
return output.join('\n');
|
|
75
|
+
}
|
|
76
|
+
export function describeScopes(tokenType, scopes) {
|
|
77
|
+
const typeLabel = (tokenType && TOKEN_TYPE_LABEL[tokenType]) ?? '令牌';
|
|
78
|
+
if (scopes === null) {
|
|
79
|
+
return `${typeLabel}(全部能力)`;
|
|
80
|
+
}
|
|
81
|
+
const labels = scopes.map((scope) => SCOPE_LABEL[scope] ?? scope);
|
|
82
|
+
return `${typeLabel}(${labels.length > 0 ? labels.join('、') : '无可用能力'})`;
|
|
83
|
+
}
|
|
84
|
+
export async function resolveSkillScopes() {
|
|
85
|
+
const config = loadConfig();
|
|
86
|
+
let key = null;
|
|
87
|
+
try {
|
|
88
|
+
key = resolveKey(config);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
key = null;
|
|
92
|
+
}
|
|
93
|
+
if (key) {
|
|
94
|
+
try {
|
|
95
|
+
const endpoint = endpointOfEnv(resolveEnv(config));
|
|
96
|
+
const identity = await new OpenApisClient(`${endpoint}/open-apis`, key).whoami();
|
|
97
|
+
updateConfig({ tokenType: identity.tokenType, scopes: identity.scopes });
|
|
98
|
+
return identity.scopes ?? null;
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
if (error instanceof AuthError || !config?.scopes) {
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
return config.scopes;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (config?.scopes) {
|
|
108
|
+
return config.scopes;
|
|
109
|
+
}
|
|
110
|
+
throw new UsageError('未登录,无法确定可安装的 Skill', '先执行 yos login 配置访问令牌');
|
|
111
|
+
}
|
package/dist/skill-sync.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { cpSync, existsSync, mkdirSync, readdirSync, rmSync } from 'node:fs';
|
|
1
|
+
import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
3
|
import { dirname, join } from 'node:path';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
5
|
import { readPackageMeta } from './npm-meta.js';
|
|
6
6
|
import { updateConfig } from './config.js';
|
|
7
|
+
import { isSkillAllowed, renderScoped } from './skill-scope.js';
|
|
7
8
|
import { saveVersionState } from './version-state.js';
|
|
8
9
|
const DEPRECATED_SKILLS = ['yos-doc-sheet'];
|
|
9
10
|
const AGENT_SKILL_DIRS = ['.claude/skills', '.workbuddy/skills', '.cursor/skills', '.codex/skills', '.qoder/skills', '.qoder-cn/skills', '.agents/skills'];
|
|
@@ -24,17 +25,19 @@ export function detectSkillTargets() {
|
|
|
24
25
|
.map((rel) => join(homedir(), rel))
|
|
25
26
|
.filter((dir) => existsSync(dir));
|
|
26
27
|
}
|
|
27
|
-
export function installSkillsTo(targets) {
|
|
28
|
+
export function installSkillsTo(targets, scopes) {
|
|
28
29
|
const source = skillsSourceDir();
|
|
29
|
-
const
|
|
30
|
+
const allSkills = listSourceSkills();
|
|
31
|
+
const skills = allSkills.filter((skill) => isSkillAllowed(skill, scopes));
|
|
30
32
|
for (const target of targets) {
|
|
31
33
|
for (const skill of skills) {
|
|
32
34
|
const skillTarget = join(target, skill);
|
|
33
35
|
mkdirSync(skillTarget, { recursive: true });
|
|
34
36
|
cpSync(join(source, skill), skillTarget, { recursive: true });
|
|
37
|
+
renderMarkdownFiles(skillTarget, scopes);
|
|
35
38
|
}
|
|
36
|
-
for (const
|
|
37
|
-
rmSync(join(target,
|
|
39
|
+
for (const removed of [...allSkills.filter((skill) => !skills.includes(skill)), ...DEPRECATED_SKILLS]) {
|
|
40
|
+
rmSync(join(target, removed), { recursive: true, force: true });
|
|
38
41
|
}
|
|
39
42
|
}
|
|
40
43
|
updateConfig({ installedSkillDirs: targets });
|
|
@@ -44,3 +47,17 @@ export function installSkillsTo(targets) {
|
|
|
44
47
|
}
|
|
45
48
|
return skills;
|
|
46
49
|
}
|
|
50
|
+
export function listInstalledSkills(target) {
|
|
51
|
+
return listSourceSkills().filter((skill) => existsSync(join(target, skill, 'SKILL.md')));
|
|
52
|
+
}
|
|
53
|
+
function renderMarkdownFiles(dir, scopes) {
|
|
54
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
55
|
+
const path = join(dir, entry.name);
|
|
56
|
+
if (entry.isDirectory()) {
|
|
57
|
+
renderMarkdownFiles(path, scopes);
|
|
58
|
+
}
|
|
59
|
+
else if (entry.name.endsWith('.md')) {
|
|
60
|
+
writeFileSync(path, renderScoped(readFileSync(path, 'utf8'), scopes), 'utf8');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
package/dist/skills/yos/SKILL.md
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: yos
|
|
3
|
+
# @scope knowledge:manage
|
|
3
4
|
description: YOS 企业 AI 能力总入口:公司/部门/工作/个人等各类知识的检索与文档管理、云文档/云表格编写、录音转写、帮助手册、客户端升级与反馈。用户提到 yos/YOS 即使用本技能;用户问制度/流程/规范、要查或整理资料文档、要写云文档/云表格、要看会议录音转写、需要 YOS 客户端帮助时使用;不确定该用哪个 YOS 能力时先读本文件
|
|
5
|
+
# @else
|
|
6
|
+
# description: YOS 企业知识检索入口:公司/部门/工作/个人等各类知识的检索与带出处的原文作答。用户提到 yos/YOS 即使用本技能;用户问制度/流程/规范、要查资料或引用原文时使用;不确定该用哪个 YOS 能力时先读本文件
|
|
7
|
+
# @end
|
|
4
8
|
---
|
|
5
9
|
|
|
6
10
|
# YOS 能力总入口
|
|
@@ -23,30 +27,52 @@ yos ping # 只要探活,退出码即结论(0 通 / 3 网络 / 4 鉴
|
|
|
23
27
|
| 用户在问什么 | 用哪个命令 | 先读哪本 skill |
|
|
24
28
|
|---|---|---|
|
|
25
29
|
| 「公司制度/流程/规范/报销标准/产品资料」等**要一个公司里的答案** | `retrieve search` → `retrieve grep` 定位 → `retrieve read` 读原文 | yos-retrieval |
|
|
30
|
+
<!-- @scope knowledge:manage -->
|
|
26
31
|
| 「有哪些文档 / 共几份 / 文档目录结构」 | `retrieve outline`(检索层)或 `docs tree`(管理层) | yos-retrieval / yos-knowledge |
|
|
32
|
+
<!-- @else -->
|
|
33
|
+
| 「有哪些文档 / 共几份 / 文档目录结构」 | `retrieve outline` | yos-retrieval |
|
|
34
|
+
<!-- @end -->
|
|
27
35
|
| 找**配套/相关**材料、跨文档关系 | `retrieve neighbors`、`retrieve search --entity/--topic` | yos-retrieval |
|
|
36
|
+
<!-- @scope knowledge:manage -->
|
|
28
37
|
| 浏览/搜索自己的知识库与文档内容 | `kb list` `kb detail` `docs tree` `docs content` | yos-knowledge |
|
|
29
38
|
| 把知识库里的上传文件取回本地 | `docs download <node_code> --out <路径>` | yos-knowledge |
|
|
30
39
|
| 上传本地文件或目录、新建文档/文件夹、改名、移动、删除、回收站恢复 | `kb upload` `docs create` `docs mkdir` `docs update` `docs rename` `docs move` `docs delete` `docs restore` | yos-knowledge |
|
|
31
40
|
| 往知识库**写云文档**(在线文档;非办公文件) | `docs create --type cloud`、`docs update` | **先读 yos-doc**(正文是结构化 JSON,结构与编写规范都在这本) |
|
|
32
41
|
| 往知识库**写云表格**(在线表格;非办公文件) | `docs create --type sheet`、`docs update` | **先读 yos-sheet**(正文是结构化 JSON,结构与列宽等推荐做法都在这本) |
|
|
42
|
+
<!-- @end -->
|
|
43
|
+
<!-- @scope transcript:read -->
|
|
33
44
|
| 会议录音转写、纪要、逐句发言 | `transcript list` → `transcript detail` | yos-transcript |
|
|
45
|
+
<!-- @end -->
|
|
46
|
+
<!-- @scope support -->
|
|
34
47
|
| 「YOS 怎么用」、客户端最新版本、提交问题反馈 | `support manual*` `support upgrade*` `support feedback` | yos-support |
|
|
48
|
+
<!-- @end -->
|
|
35
49
|
| 领域命令没覆盖的能力 | `tool list` → `tool schema <name>` → `tool call <name> --params '{...}'` | yos-shared |
|
|
36
50
|
|
|
51
|
+
<!-- @scope knowledge:manage -->
|
|
37
52
|
五个领域共 28 个命令(kb 4 / docs 11 / retrieve 5 / support 6 / transcript 2)。服务端工具清单以 `yos tool list` 动态获取为准,命令与工具基本 1:1,例外是 `docs download` 与 `kb upload`——两者因需读写本地文件而单独实现(后者走开放接口上传通道,不对应 MCP 工具)。`yos <领域> --help` 列出该域全部命令,`yos <领域> <动作> --help` 给出用法、参数说明与风险标注(只读 / 写入 / 高危)。
|
|
53
|
+
<!-- @else -->
|
|
54
|
+
服务端工具清单以 `yos tool list` 动态获取为准:当前令牌仅开放知识库检索(`retrieve *` 与 `kb list`),其余领域命令会被服务端拒绝(`当前令牌仅支持知识库检索`),遇到时直接告知用户该能力需在 YOS 客户端内使用,不要换写法重试。`yos <领域> <动作> --help` 给出用法、参数说明与风险标注。
|
|
55
|
+
<!-- @end -->
|
|
38
56
|
|
|
57
|
+
<!-- @scope knowledge:manage -->
|
|
39
58
|
**新建与删除知识库都不在 CLI 与服务端工具集内**:用户提到建库或删库时,引导其到 YOS 客户端手动操作,不要尝试 `yos kb create` / `yos kb delete`(会被拒绝,exit=2)。建好库之后用 `yos kb list` 取知识库编码即可继续上传与整理。
|
|
40
59
|
|
|
41
|
-
|
|
60
|
+
<!-- @end -->
|
|
61
|
+
## 2. 硬规则(违反必出错)
|
|
42
62
|
|
|
43
63
|
1. **`--json` 是双层包装**:外层 `{"text":"<JSON 字符串>","isError":false}`,要拿字段必须对 `text` 再 `JSON.parse` 一次;`isError:true` 时 `text` 是错误文案而非数据
|
|
44
64
|
2. **参数错误一律 exit=2 且不发请求**:非法枚举、越界 `--size`、日期格式非法或区间倒置、URN 非法、必填缺失都由 CLI 本地拦下,照 `提示:` 改参数即可,不要重试原命令。exit=0 仍需自行校验内容的场景见 yos-shared
|
|
45
65
|
3. **引用作答必须读原文**:`retrieve search` 的 `snippet` 只是线索,不能作为引用依据;未 `retrieve read` 之前不下结论
|
|
66
|
+
<!-- @scope knowledge:manage -->
|
|
46
67
|
4. **写操作先复述再执行**:`kb update`、`docs create/update/mkdir/rename/move`、`kb upload`、`support feedback` 都要让用户确认最终文案;`docs update` 是**整体覆盖**(正文传什么就替换什么);写云文档/云表格(`--type cloud/sheet`)的正文前**先读 yos-doc(云文档)/ yos-sheet(云表格)技能**——正文是结构化 JSON 且服务端不校验,写错要到客户端打开才暴露
|
|
47
68
|
5. **删除必须两步**:`yos docs count <node_code>` 查受影响文档数 → 展示给用户 → 用户明确同意后才 `yos docs delete`。未经确认不得调用
|
|
69
|
+
<!-- @end -->
|
|
48
70
|
6. **令牌不出现在任何输出里**:不写进日志、命令、对用户的回复;只以掩码形式(`xxxxxxxx****xxxx`,即前 8 位 + `****` + 后 4 位)引用
|
|
71
|
+
<!-- @scope transcript:read,support -->
|
|
49
72
|
7. **日期参数分两类,别混用**:`transcript list --start/--end`、`support upgrade-log --start/--end` **只收 `yyyy-MM-dd`**,中文表达由 CLI 本地拒绝(`错误: --start 日期格式应为 yyyy-MM-dd:本周`,exit 2),须自己换算;`retrieve search/outline` 的 `--occurred-*`/`--effective-*` **收自然语言**(`上季度`、`8 月` 直接传,由服务端解析),`retrieve search` 还会把 `--query` 文本里的时间表达解析为时间窗并在 `time_window` 回显
|
|
73
|
+
<!-- @else -->
|
|
74
|
+
7. **检索的日期参数收自然语言**:`retrieve search/outline` 的 `--occurred-*`/`--effective-*` 直接传 `上季度`、`8 月` 等表达,由服务端解析;`retrieve search` 还会把 `--query` 文本里的时间表达解析为时间窗并在 `time_window` 回显
|
|
75
|
+
<!-- @end -->
|
|
50
76
|
|
|
51
77
|
## 3. 登录与配置
|
|
52
78
|
|
|
@@ -64,6 +90,7 @@ yos kb list --scope created --json # 需要 kbCode 时
|
|
|
64
90
|
yos retrieve search '报销标准' --kb KB20261009000001 # 语义检索拿候选与命中行号
|
|
65
91
|
yos retrieve read 'cortex://kb/KB20261009000001/doc/ND20261009000012:1-60' # 读原文再作答
|
|
66
92
|
|
|
93
|
+
<!-- @scope knowledge:manage -->
|
|
67
94
|
# 整理知识库
|
|
68
95
|
yos docs tree KB20261009000001 # 目录树(资源编码字段是 resourceCode)
|
|
69
96
|
yos docs mkdir '会议纪要' --kb KB20261009000001 # 返回新节点编码
|
|
@@ -78,13 +105,18 @@ yos docs create "值班排期表" --kb KB20261009000001 --type sheet --file draf
|
|
|
78
105
|
yos docs content ND20261010000030 --json # 写后自查:读回确认正文完整落库、结构未变形
|
|
79
106
|
yos docs update ND20261010000030 --file edited.yosdoc.json # 改正文=整体覆盖:先读回全文,本地编辑后整体回传
|
|
80
107
|
|
|
108
|
+
<!-- @end -->
|
|
109
|
+
<!-- @scope transcript:read -->
|
|
81
110
|
# 会议内容
|
|
82
111
|
yos transcript list --json # 取 transcriptionUserId(不是 TT 开头编码)
|
|
83
112
|
yos transcript detail 2105108032979103745 --json # 取 summary / sentences
|
|
84
113
|
|
|
114
|
+
<!-- @end -->
|
|
115
|
+
<!-- @scope support -->
|
|
85
116
|
# 帮助与版本
|
|
86
117
|
yos support manual-search '登录' # 手册检索
|
|
87
118
|
yos support upgrade --platform MAC_ARM64 # 客户端最新版
|
|
119
|
+
<!-- @end -->
|
|
88
120
|
```
|
|
89
121
|
|
|
90
122
|
## 5. 输出与兜底
|
|
@@ -220,7 +220,11 @@ yos retrieve neighbors 'cortex://kb/KB20260921000001/doc/ND20260921000307' --kin
|
|
|
220
220
|
|
|
221
221
|
### 做不到的事(别反复试)
|
|
222
222
|
|
|
223
|
+
<!-- @scope transcript:read -->
|
|
223
224
|
- 无跨转写全文检索:`retrieve` 不覆盖会议记录,转写正文走 `yos transcript detail`。
|
|
225
|
+
<!-- @else -->
|
|
226
|
+
- 无跨转写全文检索:`retrieve` 不覆盖会议记录。
|
|
227
|
+
<!-- @end -->
|
|
224
228
|
- 无 `--min-score` 相关度阈值;无按编辑时间排序。
|
|
225
229
|
- 不能把检索结果的 `score` 当成可信度百分比对外表述。
|
|
226
230
|
|
|
@@ -66,8 +66,12 @@ yos kb list --json | node -e 'let d="";process.stdin.on("data",c=>d+=c).on("end"
|
|
|
66
66
|
| 知识库 `kbCode` | `KB` + yyyyMMdd + 6 位序号 | `KB20260921000001` |
|
|
67
67
|
| 节点 `resourceCode` / `nodeCode` | `ND` + yyyyMMdd + 6 位序号 | `ND20260921000307` |
|
|
68
68
|
| 检索 URN | `cortex://kb/{kbCode}/doc/{nodeCode}` | `cortex://kb/KB20260921000001/doc/ND20260921000307` |
|
|
69
|
+
<!-- @scope transcript:read -->
|
|
69
70
|
| 转写记录 ID | 19 位数字字符串 `transcriptionUserId` | `2105108032979103745` |
|
|
71
|
+
<!-- @end -->
|
|
72
|
+
<!-- @scope support -->
|
|
70
73
|
| 手册节点 ID | 19 位数字(`support manual` 目录树里的 `id`) | `2100513671581945858` |
|
|
74
|
+
<!-- @end -->
|
|
71
75
|
|
|
72
76
|
**两套编码命名空间不互通**(跨域引用时的硬约束):
|
|
73
77
|
|
|
@@ -100,7 +104,9 @@ exit=1 的文案偶有服务端内部字段名(如 `kb_code`、`output_mode`
|
|
|
100
104
|
| 命令 | 行为 | 必做的校验 |
|
|
101
105
|
|---|---|---|
|
|
102
106
|
| `retrieve search` | 低分候选照常返回(实测 score 0.016 的不相关文档也在列表里) | 看 `score`,低于 0.3 的结果不要当依据;必要时 `retrieve read` 核对原文 |
|
|
107
|
+
<!-- @scope knowledge:manage -->
|
|
103
108
|
| `docs content`(上传的 file 类型节点) | `content` 为空,返回体带 `contentHint` 说明该节点无内联正文 | 读上传文件正文改用 `retrieve read`,取原文件用 `docs download` |
|
|
109
|
+
<!-- @end -->
|
|
104
110
|
| `retrieve grep --mode count` | `matchCount` 可能为 null(cortex 侧未回该字段) | 需要命中数时用 `--mode content` 数 `matches` 长度 |
|
|
105
111
|
| 任何检索/查询 | 空结果与「参数写错但恰好合法」不可区分(如 `--kb` 传了无权限的库) | 结果为空时先确认编码与权限,再回答「没有相关资料」 |
|
|
106
112
|
|
|
@@ -128,14 +134,21 @@ exit=1 的文案偶有服务端内部字段名(如 `kb_code`、`output_mode`
|
|
|
128
134
|
|
|
129
135
|
```bash
|
|
130
136
|
yos kb list # → kbCode(表格左列;末尾有「还有 M 条」尾注时须先翻页拿全)
|
|
137
|
+
<!-- @scope knowledge:manage -->
|
|
131
138
|
yos docs tree KB20260921000001 # → resourceCode(树里每个节点的编码)
|
|
139
|
+
<!-- @end -->
|
|
132
140
|
yos retrieve outline 'cortex://kb/KB20260921000001' # → 文档 URN(含行号,检索决策用)
|
|
141
|
+
<!-- @scope transcript:read -->
|
|
133
142
|
yos transcript list # → transcriptionUserId
|
|
143
|
+
<!-- @end -->
|
|
144
|
+
<!-- @scope support -->
|
|
134
145
|
yos support manual # → 手册节点 id
|
|
146
|
+
<!-- @end -->
|
|
135
147
|
```
|
|
136
148
|
|
|
137
149
|
`--keyword` 缩小范围:`yos kb list --keyword 报销`。
|
|
138
150
|
|
|
151
|
+
<!-- @scope knowledge:manage -->
|
|
139
152
|
## 6. 权限与写操作规则
|
|
140
153
|
|
|
141
154
|
服务端按知识库角色校验,CLI 不做本地校验,权限不足直接返回业务失败(退出码 1):
|
|
@@ -149,8 +162,15 @@ yos support manual # → 手册节点 id
|
|
|
149
162
|
- `kb list` / `docs tree` 返回的 `role` 字段实测取值:`owner`(所有者)/ `admin` / `edit` / `read`(只读分享),无直接角色时为 `null`
|
|
150
163
|
- 权限不足是**运行时**返回的业务失败(exit 1),文案形如 `没有该资源的访问权限:MOVE_DELETE_RESOURCE.ND20261010000018`:含节点编码但不告诉你缺什么角色。正确做法:先 `yos kb detail <kbCode>` 看 `role`,再决定是否执行;只有 `read`/`null` 时直接告知用户需要申请编辑或管理权限
|
|
151
164
|
- **建库与删库都不在 CLI 内**(服务端未提供 `kb_create` / `kb_delete` 工具):用户要新建或删除知识库,引导其去 YOS 客户端手动操作;建好库后用 `yos kb list` 取编码继续后续动作
|
|
165
|
+
<!-- @else -->
|
|
166
|
+
## 6. 权限范围
|
|
167
|
+
|
|
168
|
+
当前令牌仅开放知识库检索(`retrieve *` 与 `kb list`)。文档管理、转写查询、帮助与反馈等能力会被服务端拒绝(`当前令牌仅支持知识库检索,该能力请在 YOS 客户端内使用`),遇到时直接告知用户需在 YOS 客户端内操作,不要换写法重试。
|
|
169
|
+
|
|
170
|
+
<!-- @end -->
|
|
152
171
|
- `retrieve` 只能命中当前用户可见的文档:跨库检索范围随登录身份变化,换令牌结果就不同
|
|
153
172
|
|
|
173
|
+
<!-- @scope knowledge:manage -->
|
|
154
174
|
## 7. 删除与安全纪律(强制)
|
|
155
175
|
|
|
156
176
|
1. 删除前必须先查影响面并向用户报告,拿到明确确认才执行:
|
|
@@ -162,18 +182,31 @@ yos support manual # → 手册节点 id
|
|
|
162
182
|
3. 写入类命令(`kb update`、`docs mkdir/create/update/rename/move/restore`、`kb upload`、`support feedback`)在用户没有明确要求时不擅自执行;`support feedback` 会真实提交工单,必须原文让用户确认内容后再发
|
|
163
183
|
4. 正文内容含用户数据时注意:`--content` 会进入 shell 历史,长文本/多行文本一律改走 `--file <路径>`
|
|
164
184
|
|
|
185
|
+
<!-- @end -->
|
|
165
186
|
## 8. 底层工具通道(领域命令覆盖不到时才用)
|
|
166
187
|
|
|
167
188
|
```bash
|
|
168
189
|
yos tool list # 全部工具,按领域分组(动态获取,以实际输出为准)
|
|
169
190
|
yos tool schema retrieve_search # 完整描述 + 入参表 + 返参 + 调用示例
|
|
191
|
+
<!-- @scope knowledge:manage -->
|
|
170
192
|
yos tool call docs_tree --params '{"kb_code":"KB20260921000001"}'
|
|
193
|
+
<!-- @else -->
|
|
194
|
+
yos tool call kb_list --params '{"keyword":"报销"}'
|
|
195
|
+
<!-- @end -->
|
|
171
196
|
```
|
|
172
197
|
|
|
173
198
|
- `tool schema` 的入参说明会截断到 50 字,要全文用 `--json`:`yos tool schema retrieve_search --json`
|
|
174
199
|
- `tool call` 的 `--params` 必须是合法 JSON 字符串,参数名用工具 schema 里的 **snake_case**
|
|
200
|
+
<!-- @scope knowledge:manage -->
|
|
175
201
|
- 工具名容忍空格与连字符写法:`yos tool schema docs tree` / `support manual-read` 都会归一化为 `docs_tree` / `support_manual_read`
|
|
202
|
+
<!-- @else -->
|
|
203
|
+
- 工具名容忍空格与连字符写法:`yos tool schema retrieve search` 会归一化为 `retrieve_search`
|
|
204
|
+
<!-- @end -->
|
|
205
|
+
<!-- @scope knowledge:manage -->
|
|
176
206
|
- 域命令是工具的一一映射(`kb upload` 除外,走 multipart 直传),能用域命令就别用 `tool call`
|
|
207
|
+
<!-- @else -->
|
|
208
|
+
- 域命令是工具的一一映射,能用域命令就别用 `tool call`
|
|
209
|
+
<!-- @end -->
|
|
177
210
|
|
|
178
211
|
## 9. 升级与版本更新约定
|
|
179
212
|
|