@24klynx/cli 0.1.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/dist/break-cache-B716oddK.mjs +71 -0
- package/dist/break-cache-B716oddK.mjs.map +1 -0
- package/dist/bughunter-DeAizlBM.mjs +32 -0
- package/dist/bughunter-DeAizlBM.mjs.map +1 -0
- package/dist/clear-C1dFE5aD.mjs +24 -0
- package/dist/clear-C1dFE5aD.mjs.map +1 -0
- package/dist/config-D-xVXTXi.mjs +2 -0
- package/dist/config-Des0z-k9.mjs +147 -0
- package/dist/config-Des0z-k9.mjs.map +1 -0
- package/dist/context-BmZ8VEan.mjs +128 -0
- package/dist/context-BmZ8VEan.mjs.map +1 -0
- package/dist/context-viz-2ZZaTL2C.mjs +61 -0
- package/dist/context-viz-2ZZaTL2C.mjs.map +1 -0
- package/dist/env-CeeZcoDI.mjs +55 -0
- package/dist/env-CeeZcoDI.mjs.map +1 -0
- package/dist/git-branch-Dn1CP6An.mjs +96 -0
- package/dist/git-branch-Dn1CP6An.mjs.map +1 -0
- package/dist/headless-launcher-I8NWyD6k.mjs +171 -0
- package/dist/headless-launcher-I8NWyD6k.mjs.map +1 -0
- package/dist/index.d.mts +970 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +3243 -0
- package/dist/index.mjs.map +1 -0
- package/dist/memory-gnURjOnQ.mjs +199 -0
- package/dist/memory-gnURjOnQ.mjs.map +1 -0
- package/dist/privacy-B6Rm1Xck.mjs +114 -0
- package/dist/privacy-B6Rm1Xck.mjs.map +1 -0
- package/dist/process-lifecycle-Dg6n2QS-.mjs +784 -0
- package/dist/process-lifecycle-Dg6n2QS-.mjs.map +1 -0
- package/dist/sandbox-toggle-9akjTw3h.mjs +64 -0
- package/dist/sandbox-toggle-9akjTw3h.mjs.map +1 -0
- package/dist/stats-DjKezhTJ.mjs +73 -0
- package/dist/stats-DjKezhTJ.mjs.map +1 -0
- package/dist/status-B3Tw-Ef4.mjs +92 -0
- package/dist/status-B3Tw-Ef4.mjs.map +1 -0
- package/dist/upgrade-CREWRNeC.mjs +72 -0
- package/dist/upgrade-CREWRNeC.mjs.map +1 -0
- package/package.json +39 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
//#region src/commands/memory.ts
|
|
2
|
+
/**
|
|
3
|
+
* 处理 /memory 命令。
|
|
4
|
+
*
|
|
5
|
+
* 根据 action 参数返回对应的中文指令,
|
|
6
|
+
* 引导模型执行相应的 memory_write 工具调用。
|
|
7
|
+
*/
|
|
8
|
+
function handleMemoryCommand(args) {
|
|
9
|
+
switch (args.action ?? "list") {
|
|
10
|
+
case "list": return buildListInstruction();
|
|
11
|
+
case "search": return buildSearchInstruction(args.query);
|
|
12
|
+
case "add": return buildAddInstruction(args.name);
|
|
13
|
+
case "delete": return buildDeleteInstruction(args.name);
|
|
14
|
+
case "compact": return buildCompactInstruction();
|
|
15
|
+
case "export": return buildExportInstruction();
|
|
16
|
+
default: return buildListInstruction();
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/** 构建 list 操作指令 */
|
|
20
|
+
function buildListInstruction() {
|
|
21
|
+
return { instruction: [
|
|
22
|
+
"# 记忆管理 — 列出所有记忆",
|
|
23
|
+
"",
|
|
24
|
+
"用户请求列出所有已保存的记忆。请按以下步骤处理:",
|
|
25
|
+
"",
|
|
26
|
+
"1. 调用 memory_write 工具,action 参数设为 \"list\"",
|
|
27
|
+
"2. 将返回的记忆列表按以下格式展示给用户:",
|
|
28
|
+
"",
|
|
29
|
+
"```",
|
|
30
|
+
"=== 已保存的记忆(共 N 条) ===",
|
|
31
|
+
"",
|
|
32
|
+
"1. 记忆名称 — 描述",
|
|
33
|
+
" - 类型:user / feedback / project / reference",
|
|
34
|
+
" - 最后更新:YYYY-MM-DD HH:mm",
|
|
35
|
+
"",
|
|
36
|
+
"2. ...",
|
|
37
|
+
"```",
|
|
38
|
+
"",
|
|
39
|
+
"3. 如果没有任何记忆,告知用户:「当前没有任何已保存的记忆。",
|
|
40
|
+
" 使用 /memory add <名称> 来创建第一条记忆。」"
|
|
41
|
+
].join("\n") };
|
|
42
|
+
}
|
|
43
|
+
/** 构建 search 操作指令 */
|
|
44
|
+
function buildSearchInstruction(query) {
|
|
45
|
+
const searchQuery = query ?? "(用户未指定查询词)";
|
|
46
|
+
return { instruction: [
|
|
47
|
+
"# 记忆管理 — 搜索记忆",
|
|
48
|
+
"",
|
|
49
|
+
`用户请求搜索记忆,查询词:**${searchQuery}**`,
|
|
50
|
+
"",
|
|
51
|
+
"请按以下步骤处理:",
|
|
52
|
+
"",
|
|
53
|
+
"1. 调用 memory_write 工具,action 参数设为 \"search\",将查询词作为参数传入",
|
|
54
|
+
"2. 对返回的结果,按相关度从高到低列出:",
|
|
55
|
+
"",
|
|
56
|
+
"```",
|
|
57
|
+
`=== 搜索结果:"${searchQuery}" ===`,
|
|
58
|
+
"",
|
|
59
|
+
"1. 记忆名称 — 相关度评分",
|
|
60
|
+
" - 描述",
|
|
61
|
+
" - 内容摘要(前 200 字符)",
|
|
62
|
+
"",
|
|
63
|
+
"2. ...",
|
|
64
|
+
"```",
|
|
65
|
+
"",
|
|
66
|
+
`3. 如果没有匹配结果,告知用户:「未找到与 "${searchQuery}" 相关的记忆。」`,
|
|
67
|
+
" 建议用户尝试其他关键词或使用 /memory list 浏览全部记忆。"
|
|
68
|
+
].join("\n") };
|
|
69
|
+
}
|
|
70
|
+
/** 构建 add 操作指令 */
|
|
71
|
+
function buildAddInstruction(name) {
|
|
72
|
+
if (name && name.trim()) return { instruction: [
|
|
73
|
+
"# 记忆管理 — 添加记忆",
|
|
74
|
+
"",
|
|
75
|
+
`用户请求添加名为 **${name}** 的记忆。`,
|
|
76
|
+
"",
|
|
77
|
+
"请按以下步骤处理:",
|
|
78
|
+
"",
|
|
79
|
+
`1. 首先向用户询问该记忆的内容:「请提供 "${name}" 记忆的具体内容。」`,
|
|
80
|
+
"2. 收到内容后,调用 memory_write 工具:",
|
|
81
|
+
` - action: "create"`,
|
|
82
|
+
` - name: "${name}"`,
|
|
83
|
+
" - content: 用户提供的内容",
|
|
84
|
+
` - description: 根据内容生成简短描述(可选)`,
|
|
85
|
+
` - type: 根据内容选择类型:user / feedback / project / reference`,
|
|
86
|
+
`3. 确认保存成功后告知用户:「记忆 "${name}" 已保存。」`,
|
|
87
|
+
"",
|
|
88
|
+
"如果用户已经提供了完整内容(而非只给名称),则直接保存,无需再次询问。"
|
|
89
|
+
].join("\n") };
|
|
90
|
+
return { instruction: [
|
|
91
|
+
"# 记忆管理 — 添加记忆",
|
|
92
|
+
"",
|
|
93
|
+
"用户请求添加新记忆,但未指定名称。",
|
|
94
|
+
"",
|
|
95
|
+
"请按以下步骤处理:",
|
|
96
|
+
"",
|
|
97
|
+
"1. 询问用户:「请提供记忆的名称和内容。格式:名称 内容」",
|
|
98
|
+
"2. 收到名称和内容后,调用 memory_write 工具:",
|
|
99
|
+
" - action: \"create\"",
|
|
100
|
+
" - name: 用户提供的名称",
|
|
101
|
+
" - content: 用户提供的内容",
|
|
102
|
+
" - description: 根据内容生成简短描述(可选)",
|
|
103
|
+
" - type: 根据内容选择类型:user / feedback / project / reference",
|
|
104
|
+
"3. 确认保存成功后告知用户:「记忆 \"<名称>\" 已保存。」"
|
|
105
|
+
].join("\n") };
|
|
106
|
+
}
|
|
107
|
+
/** 构建 delete 操作指令 */
|
|
108
|
+
function buildDeleteInstruction(name) {
|
|
109
|
+
if (name && name.trim()) return { instruction: [
|
|
110
|
+
"# 记忆管理 — 删除记忆",
|
|
111
|
+
"",
|
|
112
|
+
`用户请求删除名为 **${name}** 的记忆。`,
|
|
113
|
+
"",
|
|
114
|
+
"请按以下步骤处理:",
|
|
115
|
+
"",
|
|
116
|
+
"1. 先调用 memory_write 工具获取该记忆的内容(action: \"get\"),向用户展示确认",
|
|
117
|
+
`2. 询问用户确认:「确认删除记忆 "${name}"?此操作不可撤销。(回复 是/否)」`,
|
|
118
|
+
"3. 用户确认后,调用 memory_write 工具:",
|
|
119
|
+
` - action: "delete"`,
|
|
120
|
+
` - name: "${name}"`,
|
|
121
|
+
`4. 告知用户:「记忆 "${name}" 已删除。」`,
|
|
122
|
+
"",
|
|
123
|
+
`如果步骤 1 未找到该记忆,告知用户:「记忆 "${name}" 不存在。」`
|
|
124
|
+
].join("\n") };
|
|
125
|
+
return { instruction: [
|
|
126
|
+
"# 记忆管理 — 删除记忆",
|
|
127
|
+
"",
|
|
128
|
+
"用户请求删除记忆,但未指定名称。",
|
|
129
|
+
"",
|
|
130
|
+
"请按以下步骤处理:",
|
|
131
|
+
"",
|
|
132
|
+
"1. 先调用 memory_write 工具列出所有记忆(action: \"list\"),展示给用户",
|
|
133
|
+
"2. 询问用户:「请指定要删除的记忆名称。」",
|
|
134
|
+
"3. 收到名称后,展示记忆内容并请求二次确认",
|
|
135
|
+
"4. 确认后调用 memory_write tool (action: \"delete\") 删除",
|
|
136
|
+
"5. 告知用户结果"
|
|
137
|
+
].join("\n") };
|
|
138
|
+
}
|
|
139
|
+
/** 构建 compact 操作指令 */
|
|
140
|
+
function buildCompactInstruction() {
|
|
141
|
+
return { instruction: [
|
|
142
|
+
"# 记忆管理 — 去重压缩",
|
|
143
|
+
"",
|
|
144
|
+
"用户请求对记忆进行去重压缩。",
|
|
145
|
+
"",
|
|
146
|
+
"请按以下步骤处理:",
|
|
147
|
+
"",
|
|
148
|
+
"1. 调用 memory_write 工具,action 参数设为 \"compact\"",
|
|
149
|
+
"2. 工具会对所有记忆进行 Jaccard 相似度检测,合并高度相似的条目",
|
|
150
|
+
"3. 将结果展示给用户:",
|
|
151
|
+
"",
|
|
152
|
+
"```",
|
|
153
|
+
"=== 记忆去重压缩结果 ===",
|
|
154
|
+
"",
|
|
155
|
+
"处理前:N 条记忆",
|
|
156
|
+
"处理后:M 条记忆",
|
|
157
|
+
"合并/删除:K 条",
|
|
158
|
+
"",
|
|
159
|
+
"合并详情:",
|
|
160
|
+
" \"条目A\" + \"条目B\" → \"条目A\"(保留更长内容)",
|
|
161
|
+
" ...",
|
|
162
|
+
"```",
|
|
163
|
+
"",
|
|
164
|
+
"4. 如果没有需要合并的条目,告知用户:「所有记忆内容差异较大,无需合并。」"
|
|
165
|
+
].join("\n") };
|
|
166
|
+
}
|
|
167
|
+
/** 构建 export 操作指令 */
|
|
168
|
+
function buildExportInstruction() {
|
|
169
|
+
return { instruction: [
|
|
170
|
+
"# 记忆管理 — 导出记忆",
|
|
171
|
+
"",
|
|
172
|
+
"用户请求导出所有记忆。",
|
|
173
|
+
"",
|
|
174
|
+
"请按以下步骤处理:",
|
|
175
|
+
"",
|
|
176
|
+
"1. 调用 memory_write 工具,action 参数设为 \"export\"",
|
|
177
|
+
"2. 工具会返回所有记忆的 JSON 字符串",
|
|
178
|
+
"3. 将 JSON 内容格式化后展示给用户,并用代码块包裹:",
|
|
179
|
+
"",
|
|
180
|
+
"```json",
|
|
181
|
+
"[",
|
|
182
|
+
" {",
|
|
183
|
+
" \"name\": \"...\",",
|
|
184
|
+
" \"description\": \"...\",",
|
|
185
|
+
" \"content\": \"...\",",
|
|
186
|
+
" \"metadata\": { ... }",
|
|
187
|
+
" },",
|
|
188
|
+
" ...",
|
|
189
|
+
"]",
|
|
190
|
+
"```",
|
|
191
|
+
"",
|
|
192
|
+
"4. 询问用户是否需要保存到文件(使用 write_file 工具写入)。",
|
|
193
|
+
"5. 如果没有记忆,告知用户:「当前没有任何记忆可以导出。」"
|
|
194
|
+
].join("\n") };
|
|
195
|
+
}
|
|
196
|
+
//#endregion
|
|
197
|
+
export { handleMemoryCommand };
|
|
198
|
+
|
|
199
|
+
//# sourceMappingURL=memory-gnURjOnQ.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-gnURjOnQ.mjs","names":[],"sources":["../src/commands/memory.ts"],"sourcesContent":["/**\n * /memory — 记忆管理命令。\n *\n * 返回一段中文指令,引导模型使用 memory_write 工具\n * 进行记忆的列出、搜索、添加、删除、去重和导出操作。\n *\n * 用法:/memory [list|search|add|delete|compact|export] [名称或查询]\n */\n\n// ── Types ──────────────────────────────────────────────\n\n/** 记忆命令参数 */\nexport interface MemoryCommandArgs {\n /** 操作:list(默认)、search、add、delete、compact、export */\n action?: \"list\" | \"search\" | \"add\" | \"delete\" | \"compact\" | \"export\";\n /** 搜索查询或条目名称 */\n query?: string;\n /** 条目名称(用于 add/delete) */\n name?: string;\n}\n\n// ── Public API ─────────────────────────────────────────\n\n/**\n * 处理 /memory 命令。\n *\n * 根据 action 参数返回对应的中文指令,\n * 引导模型执行相应的 memory_write 工具调用。\n */\nexport function handleMemoryCommand(args: MemoryCommandArgs): { instruction: string } {\n const action = args.action ?? \"list\";\n\n switch (action) {\n case \"list\":\n return buildListInstruction();\n case \"search\":\n return buildSearchInstruction(args.query);\n case \"add\":\n return buildAddInstruction(args.name);\n case \"delete\":\n return buildDeleteInstruction(args.name);\n case \"compact\":\n return buildCompactInstruction();\n case \"export\":\n return buildExportInstruction();\n default:\n return buildListInstruction();\n }\n}\n\n// ── 各操作指令构建 ─────────────────────────────────────\n\n/** 构建 list 操作指令 */\nfunction buildListInstruction(): { instruction: string } {\n const lines: string[] = [\n \"# 记忆管理 — 列出所有记忆\",\n \"\",\n \"用户请求列出所有已保存的记忆。请按以下步骤处理:\",\n \"\",\n '1. 调用 memory_write 工具,action 参数设为 \"list\"',\n \"2. 将返回的记忆列表按以下格式展示给用户:\",\n \"\",\n \"```\",\n \"=== 已保存的记忆(共 N 条) ===\",\n \"\",\n \"1. 记忆名称 — 描述\",\n \" - 类型:user / feedback / project / reference\",\n \" - 最后更新:YYYY-MM-DD HH:mm\",\n \"\",\n \"2. ...\",\n \"```\",\n \"\",\n \"3. 如果没有任何记忆,告知用户:「当前没有任何已保存的记忆。\",\n \" 使用 /memory add <名称> 来创建第一条记忆。」\",\n ];\n return { instruction: lines.join(\"\\n\") };\n}\n\n/** 构建 search 操作指令 */\nfunction buildSearchInstruction(query?: string): { instruction: string } {\n const searchQuery = query ?? \"(用户未指定查询词)\";\n const lines: string[] = [\n \"# 记忆管理 — 搜索记忆\",\n \"\",\n `用户请求搜索记忆,查询词:**${searchQuery}**`,\n \"\",\n \"请按以下步骤处理:\",\n \"\",\n '1. 调用 memory_write 工具,action 参数设为 \"search\",将查询词作为参数传入',\n \"2. 对返回的结果,按相关度从高到低列出:\",\n \"\",\n \"```\",\n `=== 搜索结果:\"${searchQuery}\" ===`,\n \"\",\n \"1. 记忆名称 — 相关度评分\",\n \" - 描述\",\n \" - 内容摘要(前 200 字符)\",\n \"\",\n \"2. ...\",\n \"```\",\n \"\",\n `3. 如果没有匹配结果,告知用户:「未找到与 \"${searchQuery}\" 相关的记忆。」`,\n \" 建议用户尝试其他关键词或使用 /memory list 浏览全部记忆。\",\n ];\n return { instruction: lines.join(\"\\n\") };\n}\n\n/** 构建 add 操作指令 */\nfunction buildAddInstruction(name?: string): { instruction: string } {\n if (name && name.trim()) {\n const lines: string[] = [\n \"# 记忆管理 — 添加记忆\",\n \"\",\n `用户请求添加名为 **${name}** 的记忆。`,\n \"\",\n \"请按以下步骤处理:\",\n \"\",\n `1. 首先向用户询问该记忆的内容:「请提供 \"${name}\" 记忆的具体内容。」`,\n \"2. 收到内容后,调用 memory_write 工具:\",\n ` - action: \"create\"`,\n ` - name: \"${name}\"`,\n \" - content: 用户提供的内容\",\n ` - description: 根据内容生成简短描述(可选)`,\n ` - type: 根据内容选择类型:user / feedback / project / reference`,\n `3. 确认保存成功后告知用户:「记忆 \"${name}\" 已保存。」`,\n \"\",\n \"如果用户已经提供了完整内容(而非只给名称),则直接保存,无需再次询问。\",\n ];\n return { instruction: lines.join(\"\\n\") };\n }\n\n const lines: string[] = [\n \"# 记忆管理 — 添加记忆\",\n \"\",\n \"用户请求添加新记忆,但未指定名称。\",\n \"\",\n \"请按以下步骤处理:\",\n \"\",\n \"1. 询问用户:「请提供记忆的名称和内容。格式:名称 内容」\",\n \"2. 收到名称和内容后,调用 memory_write 工具:\",\n ' - action: \"create\"',\n \" - name: 用户提供的名称\",\n \" - content: 用户提供的内容\",\n \" - description: 根据内容生成简短描述(可选)\",\n \" - type: 根据内容选择类型:user / feedback / project / reference\",\n '3. 确认保存成功后告知用户:「记忆 \"<名称>\" 已保存。」',\n ];\n return { instruction: lines.join(\"\\n\") };\n}\n\n/** 构建 delete 操作指令 */\nfunction buildDeleteInstruction(name?: string): { instruction: string } {\n if (name && name.trim()) {\n const lines: string[] = [\n \"# 记忆管理 — 删除记忆\",\n \"\",\n `用户请求删除名为 **${name}** 的记忆。`,\n \"\",\n \"请按以下步骤处理:\",\n \"\",\n '1. 先调用 memory_write 工具获取该记忆的内容(action: \"get\"),向用户展示确认',\n `2. 询问用户确认:「确认删除记忆 \"${name}\"?此操作不可撤销。(回复 是/否)」`,\n \"3. 用户确认后,调用 memory_write 工具:\",\n ` - action: \"delete\"`,\n ` - name: \"${name}\"`,\n `4. 告知用户:「记忆 \"${name}\" 已删除。」`,\n \"\",\n `如果步骤 1 未找到该记忆,告知用户:「记忆 \"${name}\" 不存在。」`,\n ];\n return { instruction: lines.join(\"\\n\") };\n }\n\n const lines: string[] = [\n \"# 记忆管理 — 删除记忆\",\n \"\",\n \"用户请求删除记忆,但未指定名称。\",\n \"\",\n \"请按以下步骤处理:\",\n \"\",\n '1. 先调用 memory_write 工具列出所有记忆(action: \"list\"),展示给用户',\n \"2. 询问用户:「请指定要删除的记忆名称。」\",\n \"3. 收到名称后,展示记忆内容并请求二次确认\",\n '4. 确认后调用 memory_write tool (action: \"delete\") 删除',\n \"5. 告知用户结果\",\n ];\n return { instruction: lines.join(\"\\n\") };\n}\n\n/** 构建 compact 操作指令 */\nfunction buildCompactInstruction(): { instruction: string } {\n const lines: string[] = [\n \"# 记忆管理 — 去重压缩\",\n \"\",\n \"用户请求对记忆进行去重压缩。\",\n \"\",\n \"请按以下步骤处理:\",\n \"\",\n '1. 调用 memory_write 工具,action 参数设为 \"compact\"',\n \"2. 工具会对所有记忆进行 Jaccard 相似度检测,合并高度相似的条目\",\n \"3. 将结果展示给用户:\",\n \"\",\n \"```\",\n \"=== 记忆去重压缩结果 ===\",\n \"\",\n \"处理前:N 条记忆\",\n \"处理后:M 条记忆\",\n \"合并/删除:K 条\",\n \"\",\n \"合并详情:\",\n ' \"条目A\" + \"条目B\" → \"条目A\"(保留更长内容)',\n \" ...\",\n \"```\",\n \"\",\n \"4. 如果没有需要合并的条目,告知用户:「所有记忆内容差异较大,无需合并。」\",\n ];\n return { instruction: lines.join(\"\\n\") };\n}\n\n/** 构建 export 操作指令 */\nfunction buildExportInstruction(): { instruction: string } {\n const lines: string[] = [\n \"# 记忆管理 — 导出记忆\",\n \"\",\n \"用户请求导出所有记忆。\",\n \"\",\n \"请按以下步骤处理:\",\n \"\",\n '1. 调用 memory_write 工具,action 参数设为 \"export\"',\n \"2. 工具会返回所有记忆的 JSON 字符串\",\n \"3. 将 JSON 内容格式化后展示给用户,并用代码块包裹:\",\n \"\",\n \"```json\",\n \"[\",\n \" {\",\n ' \"name\": \"...\",',\n ' \"description\": \"...\",',\n ' \"content\": \"...\",',\n ' \"metadata\": { ... }',\n \" },\",\n \" ...\",\n \"]\",\n \"```\",\n \"\",\n \"4. 询问用户是否需要保存到文件(使用 write_file 工具写入)。\",\n \"5. 如果没有记忆,告知用户:「当前没有任何记忆可以导出。」\",\n ];\n return { instruction: lines.join(\"\\n\") };\n}\n"],"mappings":";;;;;;;AA6BA,SAAgB,oBAAoB,MAAkD;CAGpF,QAFe,KAAK,UAAU,QAE9B;EACE,KAAK,QACH,OAAO,qBAAqB;EAC9B,KAAK,UACH,OAAO,uBAAuB,KAAK,KAAK;EAC1C,KAAK,OACH,OAAO,oBAAoB,KAAK,IAAI;EACtC,KAAK,UACH,OAAO,uBAAuB,KAAK,IAAI;EACzC,KAAK,WACH,OAAO,wBAAwB;EACjC,KAAK,UACH,OAAO,uBAAuB;EAChC,SACE,OAAO,qBAAqB;CAChC;AACF;;AAKA,SAAS,uBAAgD;CAsBvD,OAAO,EAAE,aAAa;EApBpB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CAEwB,CAAC,CAAC,KAAK,IAAI,EAAE;AACzC;;AAGA,SAAS,uBAAuB,OAAyC;CACvE,MAAM,cAAc,SAAS;CAwB7B,OAAO,EAAE,aAAa;EAtBpB;EACA;EACA,kBAAkB,YAAY;EAC9B;EACA;EACA;EACA;EACA;EACA;EACA;EACA,aAAa,YAAY;EACzB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,2BAA2B,YAAY;EACvC;CAEwB,CAAC,CAAC,KAAK,IAAI,EAAE;AACzC;;AAGA,SAAS,oBAAoB,MAAwC;CACnE,IAAI,QAAQ,KAAK,KAAK,GAmBpB,OAAO,EAAE,aAAa;EAjBpB;EACA;EACA,cAAc,KAAK;EACnB;EACA;EACA;EACA,0BAA0B,KAAK;EAC/B;EACA;EACA,eAAe,KAAK;EACpB;EACA;EACA;EACA,uBAAuB,KAAK;EAC5B;EACA;CAEwB,CAAC,CAAC,KAAK,IAAI,EAAE;CAmBzC,OAAO,EAAE,aAAa;EAfpB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CAEwB,CAAC,CAAC,KAAK,IAAI,EAAE;AACzC;;AAGA,SAAS,uBAAuB,MAAwC;CACtE,IAAI,QAAQ,KAAK,KAAK,GAiBpB,OAAO,EAAE,aAAa;EAfpB;EACA;EACA,cAAc,KAAK;EACnB;EACA;EACA;EACA;EACA,sBAAsB,KAAK;EAC3B;EACA;EACA,eAAe,KAAK;EACpB,gBAAgB,KAAK;EACrB;EACA,2BAA2B,KAAK;CAER,CAAC,CAAC,KAAK,IAAI,EAAE;CAgBzC,OAAO,EAAE,aAAa;EAZpB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CAEwB,CAAC,CAAC,KAAK,IAAI,EAAE;AACzC;;AAGA,SAAS,0BAAmD;CA0B1D,OAAO,EAAE,aAAa;EAxBpB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CAEwB,CAAC,CAAC,KAAK,IAAI,EAAE;AACzC;;AAGA,SAAS,yBAAkD;CA2BzD,OAAO,EAAE,aAAa;EAzBpB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CAEwB,CAAC,CAAC,KAAK,IAAI,EAAE;AACzC"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
//#region src/commands/privacy.ts
|
|
5
|
+
/**
|
|
6
|
+
* /privacy-settings — 隐私设置面板。
|
|
7
|
+
*
|
|
8
|
+
* 管理允许/禁止的域名列表和数据分析共享选项。
|
|
9
|
+
* 配置文件位于 ~/.lynx/privacy.json。
|
|
10
|
+
*
|
|
11
|
+
* 支持三种操作:
|
|
12
|
+
* - 无参数:显示当前隐私设置
|
|
13
|
+
* - --allow <domain>:添加域名到允许列表
|
|
14
|
+
* - --deny <domain>:添加域名到禁止列表
|
|
15
|
+
*/
|
|
16
|
+
const DEFAULT_CONFIG = {
|
|
17
|
+
allowlist: [],
|
|
18
|
+
denylist: [],
|
|
19
|
+
shareAnalytics: false
|
|
20
|
+
};
|
|
21
|
+
/** 获取 privacy.json 的完整路径。 */
|
|
22
|
+
function privacyConfigPath() {
|
|
23
|
+
return join(homedir(), ".lynx", "privacy.json");
|
|
24
|
+
}
|
|
25
|
+
/** 读取当前隐私配置。文件不存在时返回默认值。 */
|
|
26
|
+
function loadPrivacyConfig() {
|
|
27
|
+
const path = privacyConfigPath();
|
|
28
|
+
if (!existsSync(path)) return { ...DEFAULT_CONFIG };
|
|
29
|
+
try {
|
|
30
|
+
const raw = readFileSync(path, "utf-8");
|
|
31
|
+
const parsed = JSON.parse(raw);
|
|
32
|
+
return {
|
|
33
|
+
allowlist: Array.isArray(parsed?.allowlist) ? parsed.allowlist : [],
|
|
34
|
+
denylist: Array.isArray(parsed?.denylist) ? parsed.denylist : [],
|
|
35
|
+
shareAnalytics: typeof parsed?.shareAnalytics === "boolean" ? parsed.shareAnalytics : false
|
|
36
|
+
};
|
|
37
|
+
} catch {
|
|
38
|
+
return { ...DEFAULT_CONFIG };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** 保存隐私配置到磁盘。 */
|
|
42
|
+
function savePrivacyConfig(config) {
|
|
43
|
+
const path = privacyConfigPath();
|
|
44
|
+
const dir = dirname(path);
|
|
45
|
+
if (!existsSync(dir)) mkdirSync(dir, {
|
|
46
|
+
mode: 448,
|
|
47
|
+
recursive: true
|
|
48
|
+
});
|
|
49
|
+
writeFileSync(path, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
50
|
+
}
|
|
51
|
+
/** 验证域名格式(基本检查:不含空格、含至少一个点)。 */
|
|
52
|
+
function isValidDomain(domain) {
|
|
53
|
+
return domain.length > 0 && !domain.includes(" ") && domain.includes(".");
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 处理 /privacy-settings 命令。
|
|
57
|
+
*
|
|
58
|
+
* 管理允许/禁止的域名列表,显示或更新隐私设置。
|
|
59
|
+
*/
|
|
60
|
+
function handlePrivacyCommand(args) {
|
|
61
|
+
const config = loadPrivacyConfig();
|
|
62
|
+
if (args.allow) {
|
|
63
|
+
if (!isValidDomain(args.allow)) return { output: `错误:「${args.allow}」不是有效的域名格式。` };
|
|
64
|
+
if (config.allowlist.includes(args.allow)) return { output: `域名 "${args.allow}" 已在允许列表中。` };
|
|
65
|
+
config.denylist = config.denylist.filter((d) => d !== args.allow);
|
|
66
|
+
config.allowlist.push(args.allow);
|
|
67
|
+
savePrivacyConfig(config);
|
|
68
|
+
return { output: `已将 "${args.allow}" 添加到允许列表。\n\n${formatSettings(config)}` };
|
|
69
|
+
}
|
|
70
|
+
if (args.deny) {
|
|
71
|
+
if (!isValidDomain(args.deny)) return { output: `错误:「${args.deny}」不是有效的域名格式。` };
|
|
72
|
+
if (config.denylist.includes(args.deny)) return { output: `域名 "${args.deny}" 已在禁止列表中。` };
|
|
73
|
+
config.allowlist = config.allowlist.filter((d) => d !== args.deny);
|
|
74
|
+
config.denylist.push(args.deny);
|
|
75
|
+
savePrivacyConfig(config);
|
|
76
|
+
return { output: `已将 "${args.deny}" 添加到禁止列表。\n\n${formatSettings(config)}` };
|
|
77
|
+
}
|
|
78
|
+
return { output: formatSettings(config) + "\n\n" + PRIVACY_POLICY };
|
|
79
|
+
}
|
|
80
|
+
/** 格式化隐私设置输出。 */
|
|
81
|
+
function formatSettings(config) {
|
|
82
|
+
return [
|
|
83
|
+
"【隐私设置】",
|
|
84
|
+
"",
|
|
85
|
+
"允许列表(allowlist):",
|
|
86
|
+
...config.allowlist.length > 0 ? config.allowlist.map((d) => ` + ${d}`) : [" (空 — 无额外允许的域名)"],
|
|
87
|
+
"",
|
|
88
|
+
"禁止列表(denylist):",
|
|
89
|
+
...config.denylist.length > 0 ? config.denylist.map((d) => ` - ${d}`) : [" (空 — 无额外禁止的域名)"],
|
|
90
|
+
"",
|
|
91
|
+
`分析数据共享:${config.shareAnalytics ? "已启用" : "已禁用"}`,
|
|
92
|
+
"",
|
|
93
|
+
"操作提示:",
|
|
94
|
+
" lynx privacy --allow <域名> 添加到允许列表",
|
|
95
|
+
" lynx privacy --deny <域名> 添加到禁止列表"
|
|
96
|
+
].join("\n");
|
|
97
|
+
}
|
|
98
|
+
/** 隐私政策简短摘要。 */
|
|
99
|
+
const PRIVACY_POLICY = [
|
|
100
|
+
"【数据隐私说明】",
|
|
101
|
+
"",
|
|
102
|
+
"Lynx 处理的数据类型:",
|
|
103
|
+
" - 对话记录:存储在 ~/.lynx/sessions/ 目录,仅本地保存",
|
|
104
|
+
" - 工具调用日志:存储在 ~/.lynx/logs/ 目录",
|
|
105
|
+
" - 配置文件:存储在 ~/.lynx/config.json",
|
|
106
|
+
"",
|
|
107
|
+
"Lynx 不会自动上传数据到任何远程服务器。",
|
|
108
|
+
"分析数据共享默认关闭,必须手动启用。",
|
|
109
|
+
"你可以通过 allowlist/denylist 控制工具可访问的域名。"
|
|
110
|
+
].join("\n");
|
|
111
|
+
//#endregion
|
|
112
|
+
export { handlePrivacyCommand };
|
|
113
|
+
|
|
114
|
+
//# sourceMappingURL=privacy-B6Rm1Xck.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"privacy-B6Rm1Xck.mjs","names":[],"sources":["../src/commands/privacy.ts"],"sourcesContent":["/**\n * /privacy-settings — 隐私设置面板。\n *\n * 管理允许/禁止的域名列表和数据分析共享选项。\n * 配置文件位于 ~/.lynx/privacy.json。\n *\n * 支持三种操作:\n * - 无参数:显示当前隐私设置\n * - --allow <domain>:添加域名到允许列表\n * - --deny <domain>:添加域名到禁止列表\n */\n\nimport { homedir } from \"node:os\";\nimport { join, dirname } from \"node:path\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\n\n// ── Types ────────────────────────────────────────────\n\nexport interface PrivacyCommandArgs {\n /** 显示当前隐私设置。 */\n show?: boolean;\n /** 将域名添加到允许列表。 */\n allow?: string;\n /** 将域名添加到禁止列表。 */\n deny?: string;\n}\n\ninterface PrivacyConfig {\n /** 允许访问的域名列表。 */\n allowlist: string[];\n /** 禁止访问的域名列表。 */\n denylist: string[];\n /** 是否共享匿名使用分析数据。 */\n shareAnalytics: boolean;\n}\n\n// ── Constants ────────────────────────────────────────\n\nconst DEFAULT_CONFIG: PrivacyConfig = {\n allowlist: [],\n denylist: [],\n shareAnalytics: false,\n};\n\n// ── Helpers ──────────────────────────────────────────\n\n/** 获取 privacy.json 的完整路径。 */\nfunction privacyConfigPath(): string {\n return join(homedir(), \".lynx\", \"privacy.json\");\n}\n\n/** 读取当前隐私配置。文件不存在时返回默认值。 */\nfunction loadPrivacyConfig(): PrivacyConfig {\n const path = privacyConfigPath();\n if (!existsSync(path)) return { ...DEFAULT_CONFIG };\n try {\n const raw = readFileSync(path, \"utf-8\");\n const parsed = JSON.parse(raw);\n return {\n allowlist: Array.isArray(parsed?.allowlist) ? parsed.allowlist : [],\n denylist: Array.isArray(parsed?.denylist) ? parsed.denylist : [],\n shareAnalytics: typeof parsed?.shareAnalytics === \"boolean\" ? parsed.shareAnalytics : false,\n };\n } catch {\n return { ...DEFAULT_CONFIG };\n }\n}\n\n/** 保存隐私配置到磁盘。 */\nfunction savePrivacyConfig(config: PrivacyConfig): void {\n const path = privacyConfigPath();\n const dir = dirname(path);\n if (!existsSync(dir)) mkdirSync(dir, { mode: 0o700, recursive: true });\n writeFileSync(path, JSON.stringify(config, null, 2) + \"\\n\", \"utf-8\");\n}\n\n/** 验证域名格式(基本检查:不含空格、含至少一个点)。 */\nfunction isValidDomain(domain: string): boolean {\n return domain.length > 0 && !domain.includes(\" \") && domain.includes(\".\");\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /privacy-settings 命令。\n *\n * 管理允许/禁止的域名列表,显示或更新隐私设置。\n */\nexport function handlePrivacyCommand(args: PrivacyCommandArgs): { output: string } {\n const config = loadPrivacyConfig();\n\n // 添加域名到允许列表\n if (args.allow) {\n if (!isValidDomain(args.allow)) {\n return { output: `错误:「${args.allow}」不是有效的域名格式。` };\n }\n if (config.allowlist.includes(args.allow)) {\n return { output: `域名 \"${args.allow}\" 已在允许列表中。` };\n }\n // 从禁止列表中移除(如果存在)\n config.denylist = config.denylist.filter((d) => d !== args.allow);\n config.allowlist.push(args.allow);\n savePrivacyConfig(config);\n return {\n output: `已将 \"${args.allow}\" 添加到允许列表。\\n\\n${formatSettings(config)}`,\n };\n }\n\n // 添加域名到禁止列表\n if (args.deny) {\n if (!isValidDomain(args.deny)) {\n return { output: `错误:「${args.deny}」不是有效的域名格式。` };\n }\n if (config.denylist.includes(args.deny)) {\n return { output: `域名 \"${args.deny}\" 已在禁止列表中。` };\n }\n // 从允许列表中移除(如果存在)\n config.allowlist = config.allowlist.filter((d) => d !== args.deny);\n config.denylist.push(args.deny);\n savePrivacyConfig(config);\n return {\n output: `已将 \"${args.deny}\" 添加到禁止列表。\\n\\n${formatSettings(config)}`,\n };\n }\n\n // 默认:显示当前设置\n return { output: formatSettings(config) + \"\\n\\n\" + PRIVACY_POLICY };\n}\n\n// ── Formatting ───────────────────────────────────────\n\n/** 格式化隐私设置输出。 */\nfunction formatSettings(config: PrivacyConfig): string {\n const lines: string[] = [\n \"【隐私设置】\",\n \"\",\n \"允许列表(allowlist):\",\n ...(config.allowlist.length > 0\n ? config.allowlist.map((d) => ` + ${d}`)\n : [\" (空 — 无额外允许的域名)\"]),\n \"\",\n \"禁止列表(denylist):\",\n ...(config.denylist.length > 0\n ? config.denylist.map((d) => ` - ${d}`)\n : [\" (空 — 无额外禁止的域名)\"]),\n \"\",\n `分析数据共享:${config.shareAnalytics ? \"已启用\" : \"已禁用\"}`,\n \"\",\n \"操作提示:\",\n \" lynx privacy --allow <域名> 添加到允许列表\",\n \" lynx privacy --deny <域名> 添加到禁止列表\",\n ];\n return lines.join(\"\\n\");\n}\n\n/** 隐私政策简短摘要。 */\nconst PRIVACY_POLICY = [\n \"【数据隐私说明】\",\n \"\",\n \"Lynx 处理的数据类型:\",\n \" - 对话记录:存储在 ~/.lynx/sessions/ 目录,仅本地保存\",\n \" - 工具调用日志:存储在 ~/.lynx/logs/ 目录\",\n \" - 配置文件:存储在 ~/.lynx/config.json\",\n \"\",\n \"Lynx 不会自动上传数据到任何远程服务器。\",\n \"分析数据共享默认关闭,必须手动启用。\",\n \"你可以通过 allowlist/denylist 控制工具可访问的域名。\",\n].join(\"\\n\");\n"],"mappings":";;;;;;;;;;;;;;;AAsCA,MAAM,iBAAgC;CACpC,WAAW,CAAC;CACZ,UAAU,CAAC;CACX,gBAAgB;AAClB;;AAKA,SAAS,oBAA4B;CACnC,OAAO,KAAK,QAAQ,GAAG,SAAS,cAAc;AAChD;;AAGA,SAAS,oBAAmC;CAC1C,MAAM,OAAO,kBAAkB;CAC/B,IAAI,CAAC,WAAW,IAAI,GAAG,OAAO,EAAE,GAAG,eAAe;CAClD,IAAI;EACF,MAAM,MAAM,aAAa,MAAM,OAAO;EACtC,MAAM,SAAS,KAAK,MAAM,GAAG;EAC7B,OAAO;GACL,WAAW,MAAM,QAAQ,QAAQ,SAAS,IAAI,OAAO,YAAY,CAAC;GAClE,UAAU,MAAM,QAAQ,QAAQ,QAAQ,IAAI,OAAO,WAAW,CAAC;GAC/D,gBAAgB,OAAO,QAAQ,mBAAmB,YAAY,OAAO,iBAAiB;EACxF;CACF,QAAQ;EACN,OAAO,EAAE,GAAG,eAAe;CAC7B;AACF;;AAGA,SAAS,kBAAkB,QAA6B;CACtD,MAAM,OAAO,kBAAkB;CAC/B,MAAM,MAAM,QAAQ,IAAI;CACxB,IAAI,CAAC,WAAW,GAAG,GAAG,UAAU,KAAK;EAAE,MAAM;EAAO,WAAW;CAAK,CAAC;CACrE,cAAc,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,IAAI,MAAM,OAAO;AACrE;;AAGA,SAAS,cAAc,QAAyB;CAC9C,OAAO,OAAO,SAAS,KAAK,CAAC,OAAO,SAAS,GAAG,KAAK,OAAO,SAAS,GAAG;AAC1E;;;;;;AASA,SAAgB,qBAAqB,MAA8C;CACjF,MAAM,SAAS,kBAAkB;CAGjC,IAAI,KAAK,OAAO;EACd,IAAI,CAAC,cAAc,KAAK,KAAK,GAC3B,OAAO,EAAE,QAAQ,OAAO,KAAK,MAAM,aAAa;EAElD,IAAI,OAAO,UAAU,SAAS,KAAK,KAAK,GACtC,OAAO,EAAE,QAAQ,OAAO,KAAK,MAAM,YAAY;EAGjD,OAAO,WAAW,OAAO,SAAS,QAAQ,MAAM,MAAM,KAAK,KAAK;EAChE,OAAO,UAAU,KAAK,KAAK,KAAK;EAChC,kBAAkB,MAAM;EACxB,OAAO,EACL,QAAQ,OAAO,KAAK,MAAM,gBAAgB,eAAe,MAAM,IACjE;CACF;CAGA,IAAI,KAAK,MAAM;EACb,IAAI,CAAC,cAAc,KAAK,IAAI,GAC1B,OAAO,EAAE,QAAQ,OAAO,KAAK,KAAK,aAAa;EAEjD,IAAI,OAAO,SAAS,SAAS,KAAK,IAAI,GACpC,OAAO,EAAE,QAAQ,OAAO,KAAK,KAAK,YAAY;EAGhD,OAAO,YAAY,OAAO,UAAU,QAAQ,MAAM,MAAM,KAAK,IAAI;EACjE,OAAO,SAAS,KAAK,KAAK,IAAI;EAC9B,kBAAkB,MAAM;EACxB,OAAO,EACL,QAAQ,OAAO,KAAK,KAAK,gBAAgB,eAAe,MAAM,IAChE;CACF;CAGA,OAAO,EAAE,QAAQ,eAAe,MAAM,IAAI,SAAS,eAAe;AACpE;;AAKA,SAAS,eAAe,QAA+B;CAoBrD,OAAO;EAlBL;EACA;EACA;EACA,GAAI,OAAO,UAAU,SAAS,IAC1B,OAAO,UAAU,KAAK,MAAM,OAAO,GAAG,IACtC,CAAC,kBAAkB;EACvB;EACA;EACA,GAAI,OAAO,SAAS,SAAS,IACzB,OAAO,SAAS,KAAK,MAAM,OAAO,GAAG,IACrC,CAAC,kBAAkB;EACvB;EACA,UAAU,OAAO,iBAAiB,QAAQ;EAC1C;EACA;EACA;EACA;CAES,CAAC,CAAC,KAAK,IAAI;AACxB;;AAGA,MAAM,iBAAiB;CACrB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC,CAAC,KAAK,IAAI"}
|